изменить цвет ячейки datagrid на основе значений

<p>у меня есть сетка данных wpf, и я хочу разные цвета ячеек в соответствии со значениями. у меня есть код ниже на моем xaml</p><pre><code>style targettype="datagridcell" </code></pre><p>но вместо выбора только ячейки выбирается вся строка? что мне не хватает?</p>

<p>если вы попытаетесь установить <code>datagrid.cellstyle</code>, datacontext будет строкой, поэтому, если вы хотите изменить цвет на основе одной ячейки, это может быть проще всего сделать в определенных столбцах, особенно если столбцы могут иметь различное содержимое, например textblocks, comboboxes и checkboxes. вот пример установки всех ячеек светло-зеленого цвета, где <code>name</code> - <code>john</code>:</p><pre><code><datagridtextcolumn binding="{binding name}"> <datagridtextcolumn.elementstyle> <style targettype="{x:type textblock}"> <style.triggers> <trigger property="text" value="john"> <setter property="background" value="lightgreen"/> </trigger> </style.triggers> </style> </datagridtextcolumn.elementstyle> </datagridtextcolumn> </code></pre><p><img src="https://i.stack.imgur.com/pbjcx.png" alt="a screenshot"></p><hr><p>вы также можете использовать <a href="http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx"><code>valueconverter</code></a> для изменения цвета.</p><pre class="lang-cs prettyprint-override"><code>public class nametobrushconverter : ivalueconverter { public object convert(object value, type targettype, object parameter, system.globalization.cultureinfo culture) { string input = value as string; switch (input) { case "john": return brushes.lightgreen; default: return dependencyproperty.unsetvalue; } } public object convertback(object value, type targettype, object parameter, system.globalization.cultureinfo culture) { throw new notsupportedexception(); } } </code></pre><p>использование:</p><pre><code><window.resources> <local:nametobrushconverter x:key="nametobrushconverter"/> </window.resources> ... <datagridtextcolumn binding="{binding name}"> <datagridtextcolumn.elementstyle> <style targettype="{x:type textblock}"> <setter property="background" value="{binding name, converter={staticresource nametobrushconverter}}"/> </style> </datagridtextcolumn.elementstyle> </datagridtextcolumn> </code></pre><hr><p>еще один вариант - напрямую связать <code>background</code> со свойством, которое возвращает соответственно окрашенную кисть. вам придется запускать уведомления об изменении свойств в настройках свойств, от которых зависит цвет.</p><p>например.</p><pre class="lang-cs prettyprint-override"><code>public string name { get { return \_name; } set { if (\_name != value) { \_name = value; onpropertychanged("name"); onpropertychanged("namebrush"); } } } public brush namebrush { get { switch (name) { case "john": return brushes.lightgreen; default: break; } return brushes.transparent; } } </code></pre>

<p>если вам нужно сделать это с заданным количеством столбцов, лучше всего использовать h.b. но если вы не знаете, сколько столбцов вы имеете дело до времени выполнения, тогда будет работать приведенный ниже код [read: hack]. я не уверен, что есть лучшее решение с неизвестным количеством столбцов. мне потребовалось два дня, чтобы работать над этим и продолжать, чтобы получить его, поэтому я придерживаюсь этого независимо.</p><p>c #</p><pre><code>public class valuetobrushconverter : ivalueconverter { public object convert(object value, type targettype, object parameter, system.globalization.cultureinfo culture) { int input; try { datagridcell dgc = (datagridcell)value; system.data.datarowview rowview = (system.data.datarowview)dgc.datacontext; input = (int)rowview.row.itemarray[dgc.column.displayindex]; } catch (invalidcastexception e) { return dependencyproperty.unsetvalue; } switch (input) { case 1: return brushes.red; case 2: return brushes.white; case 3: return brushes.blue; default: return dependencyproperty.unsetvalue; } } public object convertback(object value, type targettype, object parameter, system.globalization.cultureinfo culture) { throw new notsupportedexception(); } } </code></pre><p>xaml</p><pre><code><usercontrol.resources> <conv:valuetobrushconverter x:key="valuetobrushconverter"/> <style x:key="cellstyle" targettype="datagridcell"> <setter property="background" value="{binding relativesource={relativesource self}, converter={staticresource valuetobrushconverter}}" /> </style> </usercontrol.resources> <datagrid x:name="datagrid" cellstyle="{staticresource cellstyle}"> </datagrid> </code></pre>

<p>просто поставьте вместо</p><pre><code><style targettype="{x:datagridcell}" > </code></pre><p>но имейте в виду, что это будет нацелено на все ваши ячейки (вы нацеливаетесь на все объекты типа <code>datagridcell</code>) если вы хотите поместить стиль в соответствии с типом ячейки, я бы порекомендовал вам использовать <code>datatemplateselector</code></p><p>хороший пример можно найти в руководстве datagrid кристиана мозерса:</p><p> <a href="http://www.wpftutorial.net/datagrid.html#rowdetails">http://www.wpftutorial.net/datagrid.html#rowdetails</a> </p><p>повеселись :)</p>

<p>это может помочь вам. однако это не базовая таблица данных wpf.</p><p>я использовал devexpress с пользовательским поведением colorformatter. я не смог найти на рынке ничего такого, что бы делало это из коробки. на это у меня ушло несколько дней. мой код приведен ниже, надеюсь, это поможет кому-то там.</p><p>правка: я использовал модели представления poco и mvvm, однако вы можете изменить это, чтобы не использовать poco, если хотите.</p><p> <a href="https://i.stack.imgur.com/rpaqz.png"><img src="https://i.stack.imgur.com/rpaqz.png" alt="example"></a> </p><p>viewmodel.cs</p><pre><code>namespace viewmodel { [pocoviewmodel] public class table2dviewmodel { public itable2dview table2dview { get; set; } public datatable itemstable { get; set; } public table2dviewmodel() { } public table2dviewmodel(mainviewmodel mainviewmodel, itable2dview table2dview) : base(mainviewmodel) { table2dview = table2dview; createtable(); } private void createtable() { var dt = new datatable(); var xaxisstrings = new string[]{"x1","x2","x3"}; var yaxisstrings = new string[]{"y1","y2","y3"}; //todo determine your min, max number for your colours var minvalue = 0; var maxvalue = 100; table2dview.setcolorformatter(minvalue,maxvalue, null); //add the columns dt.columns.add(" ", typeof(string)); foreach (var x in xaxisstrings) dt.columns.add(x, typeof(double)); //add all the values double z = 0; for (var y = 0; y < yaxisstrings.length; y++) { var dr = dt.newrow(); dr[" "] = yaxisstrings[y]; for (var x = 0; x < xaxisstrings.length; x++) { //todo put your actual values here! dr[xaxisstrings[x]] = z++; //add a random values } dt.rows.add(dr); } itemstable = dt; } public static table2dviewmodel create(mainviewmodel mainviewmodel, itable2dview table2dview) { var factory = viewmodelsource.factory((mainviewmodel mainvm, itable2dview view) => new table2dviewmodel(mainvm, view)); return factory(mainviewmodel, table2dview); } } } </code></pre><p>iview.cs</p><pre><code>namespace interfaces { public interface itable2dview { void setcolorformatter(float minvalue, float maxvalue, colorscaleformat colorscaleformat); } } </code></pre><p>view.xaml.cs</p><pre><code>namespace view { public partial class table2dview : itable2dview { public table2dview() { initializecomponent(); } static colorscaleformat defaultcolorscaleformat = new colorscaleformat { colormin = (color)colorconverter.convertfromstring("#fff8696b"), colormiddle = (color)colorconverter.convertfromstring("#ffffeb84"), colormax = (color)colorconverter.convertfromstring("#ff63be7b") }; public void setcolorformatter(float minvalue, float maxvalue, colorscaleformat colorscaleformat = null) { if (colorscaleformat == null) colorscaleformat = defaultcolorscaleformat; conditionbehavior.minvalue = minvalue; conditionbehavior.maxvalue = maxvalue; conditionbehavior.colorscaleformat = colorscaleformat; } } } </code></pre><p>dynamicconditionbehavior.cs</p><pre><code>namespace behaviors { public class dynamicconditionbehavior : behavior<gridcontrol> { gridcontrol grid => associatedobject; protected override void onattached() { base.onattached(); grid.itemssourcechanged += onitemssourcechanged; } protected override void ondetaching() { grid.itemssourcechanged -= onitemssourcechanged; base.ondetaching(); } public colorscaleformat colorscaleformat { get; set;} public float minvalue { get; set; } public float maxvalue { get; set; } private void onitemssourcechanged(object sender, eventargs e) { var view = grid.view as tableview; if (view == null) return; view.formatconditions.clear(); foreach (var col in grid.columns) { view.formatconditions.add(new colorscaleformatcondition { minvalue = minvalue, maxvalue = maxvalue, fieldname = col.fieldname, format = colorscaleformat, }); } } } } </code></pre><p>view.xaml</p><pre><code><usercontrol x:class="view" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm" xmlns:viewmodels="clr-namespace:viewmodel" xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid" xmlns:behaviors="clr-namespace:behaviors" xmlns:dxdo="http://schemas.devexpress.com/winfx/2008/xaml/docking" datacontext="{dxmvvm:viewmodelsource type={x:type viewmodels:viewmodel}}" mc:ignorable="d" d:designheight="300" d:designwidth="800"> <usercontrol.resources> <style targettype="{x:type dxg:gridcolumn}"> <setter property="width" value="50"/> <setter property="horizontalheadercontentalignment" value="center"/> </style> <style targettype="{x:type dxg:headeritemscontrol}"> <setter property="fontweight" value="demibold"/> </style> </usercontrol.resources> <!--<dxmvvm:interaction.behaviors> <dxmvvm:eventtocommand eventname="" command="{binding onloadedcommand}"/> </dxmvvm:interaction.behaviors>--> <dxg:gridcontrol itemssource="{binding itemstable}" autogeneratecolumns="addnew" enablesmartcolumnsgeneration="true"> <dxmvvm:interaction.behaviors > <behaviors:dynamicconditionbehavior x:name="conditionbehavior" /> </dxmvvm:interaction.behaviors> <dxg:gridcontrol.view> <dxg:tableview showgrouppanel="false" allowperpixelscrolling="true"/> </dxg:gridcontrol.view> </dxg:gridcontrol> </usercontrol> </code></pre>

<p>в моем случае конвертор должен вернуть строковое значение. я не знаю почему, но это работает.</p><p><em>*. xaml</em> (файл общего стиля, который включен в другие файлы xaml)</p><pre><code><style targettype="datagridcell"> <setter property="background" value="{binding relativesource={relativesource self}, converter={staticresource valuetobrushconverter}}" /> </style> </code></pre><p><em>*. cs</em></p><pre><code>public object convert(object value, type targettype, object parameter, cultureinfo culture) { color color = vscolortheme.getthemedcolor(environmentcolors.toolwindowbackgroundcolorkey); return "#" + color.name; } </code></pre>

<pre><code> // example: adding a converter to a column (c#) style stylereading = new style(typeof(textblock)); setter s = new setter(); s.property = textblock.foregroundproperty; binding b = new binding(); b.relativesource = relativesource.self; b.path = new propertypath(textblock.textproperty); b.converter = new readingforegroundsetter(); s.value = b; stylereading.setters.add(s); col.elementstyle = stylereading; </code></pre>

<p>основано на ответе "кассио борги". при использовании этого метода нет необходимости менять xaml вообще.</p><pre><code> datagridtextcolumn colnamestatus2 = new datagridtextcolumn(); colnamestatus2.header = "status"; colnamestatus2.minwidth = 100; colnamestatus2.binding = new binding("status"); grdcomputer\_servives.columns.add(colnamestatus2); style style = new style(typeof(textblock)); trigger running = new trigger() { property = textblock.textproperty, value = "running" }; trigger stopped = new trigger() { property = textblock.textproperty, value = "stopped" }; stopped.setters.add(new setter() { property = textblock.backgroundproperty, value = brushes.blue }); running.setters.add(new setter() { property = textblock.backgroundproperty, value = brushes.green }); style.triggers.add(running); style.triggers.add(stopped); colnamestatus2.elementstyle = style; foreach (var service in computerresult) { var rowname = service; grdcomputer\_servives.items.add(rowname); } </code></pre>