как я могу установить ширину datagridcolumn для соответствия содержимому ("авто"), но полностью заполнить доступное пространство для datagrid в mvvm?

<p>у меня есть wpf <code>datagrid</code>, который содержит некоторые данные. я хотел бы установить ширину столбцов таким образом, чтобы содержимое помещалось и никогда не обрезалось (вместо этого должна появиться горизонтальная полоса прокрутки). кроме того, я хочу, чтобы <code>datagrid</code> заполнял все доступное место (я работаю с <code>dockpanel</code>). я использую следующий код (упрощенно):</p><pre><code><datagrid itemssource="{binding table}"> <datagrid.columns> <datagridtextcolumn minwidth="100" width="auto" header="column 1" binding="{binding property1}" /> <datagridtextcolumn minwidth="200" width="auto" header="column 2" binding="{binding property2}" /> </datagrid.columns> </datagrid> </code></pre><p>это очевидно не работает из коробки с <code>width="auto"</code>, поскольку это всегда выглядит примерно так:</p><p><img src="https://i.stack.imgur.com/kmmr2.png" alt="datagrid: only the first part of the row is marked as "selected""></p><p>это явно выглядит некрасиво. я хотел бы выбрать целую строку или, что было бы намного лучше, столбцы, чтобы заполнить всю ширину, но, как видно, это не работает.</p><p>если я вместо этого использую <code>width="*"</code>, содержимое столбцов обрезается, что для меня даже хуже.</p><p>я нашел <a href="https://stackoverflow.com/questions/3404067/wpf-datagrid-column-with-width-but-minwidth-to-fit-contents">подобный вопрос здесь</a> , и там был опубликован обходной путь. это может работать, но я работаю с шаблоном mvvm, поэтому <strong>itemssource обновляется в viewmodel</strong>, и я не могу думать о способе сделать это оттуда, потому что я не могу получить доступ к свойству <code>actualwidth</code> <code>datagridcolumn</code>. кроме того, я хотел бы сделать это только в xaml, если это возможно.</p><p>буду признателен за любую помощь. спасибо!</p><p>правка: поскольку я до сих пор не знаю, что с этим делать, я начинаю маленькую награду. я был бы очень рад предложению, что можно сделать с моей проблемой. еще раз спасибо!</p><p>правка 2: после ответа сауса я снова подумал о вариантах. проблема в том, что мне нужно обновлять свойства <code>width</code> и <code>minwidth</code> также во время работы приложения, а не только после загрузки окна. я уже пытался сделать что-то вроде</p><pre><code>column.width = new datagridlength(1, datagridlengthunittype.auto); column.minwidth = column.actualwidth; column.width = new datagridlength(1, datagridlengthunittype.star); </code></pre><p>в некоторых случаях это происходит, когда обновляется базовая <code>itemssource</code> <code>datagrid</code>. однако это не работает, так как свойство <code>actualwidth</code>, по-видимому, не изменяется после установки <code>width</code> для <code>auto</code>. есть ли возможность как-то «перекрасить» его, чтобы обновить свойство <code>actualwidth</code>? спасибо!</p>

<p>я бы предложил использовать обходной путь, с которым вы связались. это работает. в коде вашего представления добавьте следующее в конструктор после initializecomponent ():</p><pre><code>griddy.loaded += setminwidths; // i named my datagrid griddy </code></pre><p>и определите setminwidths как:</p><pre><code>public void setminwidths(object source, eventargs e ) { foreach (var column in griddy.columns) { column.minwidth = column.actualwidth; column.width = new datagridlength(1, datagridlengthunittype.star); } } </code></pre><p>я предполагаю, что причина, по которой вы не хотите использовать это решение, заключается в том, что вы считаете, что mvvm запрещает код в коде позади. но поскольку это целиком и полностью конкретная логика, я считаю, что в этом случае это оправдано. вся вещь "mvvm запрещает код в коде позади" - это немного заблуждение. </p><p>но если вы привязаны к руководствам по стилю или хотите, чтобы эта логика была доступна для всех наборов данных в вашем приложении, вы можете выполнить прикрепленное поведение, которое выполнит эту работу следующим образом:</p><pre><code>public class setminwidthtoautoattachedbehaviour { public static bool getsetminwidthtoauto(dependencyobject obj) { return (bool)obj.getvalue(setminwidthtoautoproperty); } public static void setsetminwidthtoauto(dependencyobject obj, bool value) { obj.setvalue(setminwidthtoautoproperty, value); } // using a dependencyproperty as the backing store for setminwidthtoauto. this enables animation, styling, binding, etc... public static readonly dependencyproperty setminwidthtoautoproperty = dependencyproperty.registerattached("setminwidthtoauto", typeof(bool), typeof(setminwidthtoautoattachedbehaviour), new uipropertymetadata(false, wireuploadedevent)); public static void wireuploadedevent(dependencyobject d, dependencypropertychangedeventargs e) { var grid = (datagrid)d; var doit = (bool)e.newvalue; if (doit) { grid.loaded += setminwidths; } } public static void setminwidths(object source, eventargs e) { var grid = (datagrid)source; foreach (var column in grid.columns) { column.minwidth = column.actualwidth; column.width = new datagridlength(1, datagridlengthunittype.star); } } } </code></pre><p>а затем для любой таблицы данных, к которой вы хотите применить это поведение, добавьте следующее:</p><pre><code><datagrid itemssource="{binding table}" local:setminwidthtoautoattachedbehaviour.setminwidthtoauto="true"> </code></pre><p>и тогда твоя совесть, а также твой код будут ясны.</p>

<p>используйте textblock с переносом текста внутри столбца шаблона:</p><pre><code><datagrid itemssource="{binding table}"> <datagrid.columns> <datagridtextcolumn minwidth="100" width="auto" header="column 1" binding="{binding property1}" /> <datagridtemplatecolumn width="*" header="column 2"> <datagridtemplatecolumn.celltemplate> <datatemplate> <textblock text="{binding property2}" textwrapping="wrap" /> </datatemplate> </datagridtemplatecolumn.celltemplate> </datagridtemplatecolumn> </datagrid.columns> </datagrid> </code></pre>

<p>если вы хотите, чтобы столбец никогда не обрезал ваши данные, добавьте следующее в определение window/usercontrol:</p><pre><code>xmlns:system="clr-namespace:system;assembly=mscorlib" </code></pre><p>тогда для ширины столбцов вы можете использовать следующие.</p><pre><code> width="{x:static system:double.nan}" </code></pre><p>это делает столбец всегда достаточно широким, чтобы вместить самое длинное значение в столбце.</p><p>поскольку приведенный выше код не работает в datagrid, как насчет добавления scrollviewer вокруг datagrid, например:</p><pre><code> <scrollviewer horizontalscrollbarvisibility="auto" verticalscrollbarvisibility="auto"> <datagrid itemssource="{binding table}" autogeneratecolumns="false"> <datagrid.columns> <datagridtextcolumn minwidth="10" width="auto" header="column 1" binding="{binding property1}" /> <datagridtextcolumn minwidth="200" width="*" header="column 2" binding="{binding property2}" /> </datagrid.columns> </datagrid> </scrollviewer> </code></pre>

<p>как насчет этого:</p><p>для minwidth ваших столбцов вы устанавливаете привязку к ширине scrollcontent объекта datagrid с помощью преобразователя, который делит эту ширину на количество столбцов</p><p>вам нужен некоторый код для конвертера, но это сохранит вашу структуру mvvm нетронутой.</p><p>может быть длинный выстрел, хотя, не было времени, чтобы попробовать это.</p><p><strong> правка: </strong>я еще немного подумал об этом, а там о пб: это не будет работать хорошо, если у вас есть, скажем, один огромный столбец и несколько маленьких. я предположил, что все столбцы имеют одинаковую ширину, что здесь явно не так.</p><p>вы могли бы хотеть исследовать этот путь все же. использование привязок для widths с конвертерами - это единственное, о чем я могу подумать: это может сработать: поскольку у вас есть два условия, которые необходимо учитывать при расчете ширины столбца, простого способа сделать это не будет.</p>

<p>я добавил <code>event</code> к <code>datagrid</code>, который переопределяет их ширину относительно фактической ширины <code>datagrid</code>:</p><pre><code> private static void onloaded(object sender, routedeventargs e) { datagrid dg = sender as datagrid; foreach (var column in dg.columns) { column.width = new datagridlength(dg.actualwidth / dg.columns.count, datagridlengthunittype.pixel); } } </code></pre><p>линия:</p><pre><code>column.width = new datagridlength(1, datagridlengthunittype.star); </code></pre><p>был абсолютно бессмысленным. определение <code>datagridlengthunittype.star</code> уменьшает ширину столбцов до их минимальной ширины и делает их ширину статичной и недоступной для редактирования.</p>

<p>используйте это для любого столбца, который вы хотите вписать в его содержимое: width = "sizetocells"</p>

<p>заставить последний столбец занять все оставшееся пространство в сетке данных</p><pre><code>grid.columns[grid.columns.count -1].width = new datagridlength(250, datagridlengthunittype.star); </code></pre>