c# - Datagrid ValueConverter based on Min or Max Value -
i'm trying change colour of datagrid cell based on if it's min or max value in observablecollection value of cell part of.
now have following datagrid , style template:
<grid itemssource="{binding mydata.myobscollection}"> <datagrid.resources> <style targettype="{x:type datagridcell}"> <setter property="foreground"> <setter.value> <multibinding converter="{staticresource myvalidconverter}"> <binding path="mdtime" /> //myobscollection doesn't work here <binding path="mdisvalid" /> </multibinding> </setter.value> </setter> </style>...
the collection, simplified, consists of following:
public class myclass : inotifypropertychanged { ... public observablecollection<mydata> myobscollection { get; set; }... public class mydata { public int mdtime { get; set; } public bool mdisvalid { get; set; }...
this changes value of cell colour depending on "mdisvalid" bool value, fine. want extend behaviour , if mdtime in current cell value lowest in entire collection i'm binding datagrid change colour else.
the valueconverter sits in same namespace mainwindow, not within mainwindow method. have mainwindow databound viewmodel , databinding sweet as.
i cannot figure out how access collection within valueconverter. i've tried getting datacontext of parent window, nothing seems work. i've been reading valueconverters several hours, , in every single example seems follow same basic approach. none of them seem access data outside of valueconverter method that's called, , can't figure way of passing entire collection converter.
i'm sure it's simple i've overlooked...
edit: in addition sa_ddam's answer i've added code style:
<binding relativesource="{relativesource self}"/>
and converter:
solidcolorbrush _brush = new solidcolorbrush(colors.white); var cell = (datagridcell)values[2]; string columnname = cell.column.header.tostring(); switch (columnname) { case "mdtime": return collection.min(x => x.mdtime).equals(collection[0].mdtime) ? new solidcolorbrush(colors.limegreen) : _brush; break; case "mdtime2": return collection.min(x => x.mdtime2).equals(collection[0].mdtime2) ? new solidcolorbrush(colors.limegreen) : _brush; break;...
the columnname returns actual text name of column cell in. run switch on columns have.
just need @ next 1 of refreshing table min colour change applies on single row, i.e. if smallest value in collection should 1 colour else it's another. when add on collection old colour values still apply, min query on each of cells of new row. getting there ;-)
edit #2: collection[0] first in collection, obviously, , last data add, because insert position 0. checking min value against valid validation on current row i've added, not on others. grid didn't need refreshing @ all, wasted time relaycommands did nothing. showed me had issue logic, not totally wasted time ;-)
i added simple command , returns actual data of item in question:
var celldata = cell.datacontext mydata;
then small change query , how want it:
return collection.min(x => x.mdtime).equals(celldata.mdtime)
big sa_ddam gave me first part , fumbled way need to.
i'll leave in hope helps others out, there seems lot of "simple" tutorials on web, nothing covers complex set-up. please let me know if helps out...
you can hold of itemsource
binding datagrid
, use findancestor
or name datagrid
, use elementname
in multibinding
example: (findancestor)
<datagrid itemssource="{binding mydata.myobscollection}"> <datagrid.resources> <style targettype="{x:type datagridcell}"> <setter property="foreground"> <setter.value> <multibinding converter="{staticresource myvalidconverter}"> <binding path="itemssource" relativesource="{relativesource mode=findancestor, ancestortype={x:type datagrid}}" /> <binding path="mdisvalid" /> </multibinding> </setter.value> </setter> </style>...
example: (elementname)
<datagrid x:name="datagrid" itemssource="{binding mydata.myobscollection}"> <datagrid.resources> <style targettype="{x:type datagridcell}"> <setter property="foreground"> <setter.value> <multibinding converter="{staticresource myvalidconverter}"> <binding path="itemssource" elementname="datagrid" /> <binding path="mdisvalid" /> </multibinding> </setter.value> </setter> </style>...
converter:
public object convert(object[] values, type targettype, object parameter, system.globalization.cultureinfo culture) { if (values[0] observablecollection<mydata> && values[1] int) { var collection = (observablecollection<mydata>)values[0]; var time = (int)values[1]; return collection.any() && collection.max(x => x.mdtime).equals(time) ? new solidcolorbrush(colors.red) : new solidcolorbrush(colors.black); } return new solidcolorbrush(colors.black); }
full working example
code:
namespace wpfapplication11 { /// <summary> /// interaction logic mainwindow.xaml /// </summary> public partial class mainwindow : window { private observablecollection<mydata> _items = new observablecollection<mydata>(); public mainwindow() { initializecomponent(); items.add(new mydata { title = "item1", mdtime = 1, mdtime2 =3 }); items.add(new mydata { title = "item2", mdtime = 6, mdtime2 = 50 }); items.add(new mydata { title = "item3", mdtime = 45, mdtime2 = 23 }); items.add(new mydata { title = "item4", mdtime = 3, mdtime2 = 1 }); items.add(new mydata { title = "item5", mdtime = 8, mdtime2 = 9 }); } public observablecollection<mydata> items { { return _items; } set { _items = value; } } } public class mydata { public string title { get; set; } public int mdtime { get; set; } public int mdtime2 { get; set; } public bool mdisvalid { get; set; } } public class maxconverter : imultivalueconverter { public object convert(object[] values, type targettype, object parameter, system.globalization.cultureinfo culture) { if (values[0] observablecollection<mydata> && values[1] datagridcell && values[2] mydata) { var collection = (observablecollection<mydata>)values[0]; var columnname = (values[1] datagridcell).column.header.tostring(); var data = values[2] mydata; if (columnname.equals("mdtime") && collection.max(x => x.mdtime).equals(data.mdtime)) { return new solidcolorbrush(colors.red); } else if (columnname.equals("mdtime2") && collection.min(x => x.mdtime).equals(data.mdtime)) { return new solidcolorbrush(colors.blue); } } return new solidcolorbrush(colors.black); } public object[] convertback(object value, type[] targettypes, object parameter, system.globalization.cultureinfo culture) { throw new notimplementedexception(); } } }
xaml:
<window x:class="wpfapplication11.mainwindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:wpfapplication11" title="mainwindow" height="235" width="308" name="ui"> <grid datacontext="{binding elementname=ui}" > <datagrid itemssource="{binding items}"> <datagrid.resources> <local:maxconverter x:key="myvalidconverter" /> <style targettype="{x:type datagridcell}"> <setter property="foreground"> <setter.value> <multibinding converter="{staticresource myvalidconverter}"> <binding path="itemssource" relativesource="{relativesource findancestor, ancestortype={x:type datagrid}}" /> <binding relativesource="{relativesource self}" /> <binding /> </multibinding> </setter.value> </setter> </style> </datagrid.resources> </datagrid> </grid> </window>
Comments
Post a Comment