I'm doing a budgeting module.
I will like to ask that how to set the GridViewColumn to display out my desired image based on the value which I retrieve from database which are "income" & "expenses". I know how to retrieve the value from the database & display in the lisview but my question for today is that I will like to have some condition which is when found "income" will populate with income image then found expense will populate with another image???
Can this be possible. Hope to receive reply as soon as possible. Thank you.
I will provide my codes for better refer:
XAML file:
<DataTemplate x:Key="CategoriesType">
<Border BorderBrush="#FF000000" BorderThickness="1,1,0,1" Margin="-6,-2,-6,-2">
<StackPanel Margin="6,2,6,2">
<TextBlock Text="{Binding Path=CategoriesType}"/>
</StackPanel>
</Border>
</DataTemplate>
<Style x:Key="MyItemContainerStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<!--<EventSetter Event="PreviewMouseLeftButtonDown" Handler="ListViewItem_PreviewMouseLeftButtonDown" />-->
</Style>
</Window.Resources>
<ListView Height="320" HorizontalAlignment="Left" Margin="12,154,0,0" Name="CategoriesListView" VerticalAlignment="Top" Width="316" ItemsSource="{Binding}" ItemContainerStyle="{DynamicResource MyItemContainerStyle}">
<ListView.View>
<GridView>
<GridViewColumn Header="Types" Width="40" CellTemplate="{DynamicResource CategoriesType}"/>
</GridView>
</ListView.View>
</ListView>
Add an image tag in the tamplate and use a converter to return the correct image based on the string value (untested code)
xaml:
<UserControl.Resources>
<Converters:TypeToImageConverter x:Key="typeToImageConverter" />
</UserControl.Resources>
<StackPanel Margin="6,2,6,2">
<Image Source="{Binding Path=CategoriesType,Converter={StaticResource typeToImageConverter}"/>
<TextBlock Text="{Binding Path=CategoriesType}"/>
</StackPanel>
TypeToImageConverter.cs:
public class TypeToImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
throw ...
var str = value.ToString();
if (str == "income")
return new BitmapImage(...);
if (str = "expenses")
return new BitmapImage(...);
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
I found the solution for my answer which is the format of the string. Which causing me to unavailable to retrieve the image with few hours of troubleshooting & debugging. I finally found out the solution :)
I solve it by like this:In my converter.cs
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
string str = (string)value;
string newString = str.TrimEnd();//Newly added compared with the old version
if (newString == "income")
return new BitmapImage(new Uri("pack://application:,,,/images/add.png"));
if (newString == "Expenses")
{
//return new BitmapImage(new Uri(#"pack://application:,,,/HouseWivesSavior;component/images/add.png"));
return new BitmapImage(new Uri("pack://application:,,,/images/edit.png"));
}
return null;
}
From referring the above that you can see that I added this code: "string newString = str.TrimEnd();"
Is because I don't want extra white space at the end of the string. As during insert into the database that my code is look like this:
if (IncomeButton.IsChecked == true) {
CategoryType = IncomeButton.Content.ToString();
}else{
CategoryType = ExpensesButton.Content.ToString();
}
During runtime, I found out that why the value look strange in the format of "Expenses " instead of "Expenses"... Therefore I tried with trim of the end part see how & Bingo. I got it working like a charm.
I refered this video to out that how to trace the value: http://www.youtube.com/watch?v=evO3_xutDYI
Thank you all guys for answering my question & sorry for wasting your time & effort to solve my question :) Good luck to all of you & have a nice day.
Related
I have a DataGrid containing four rows, and I would need to make the texts in the last row bold, in order to better separate them from the rows above.
I tried the methods available in the question How to change a single datagrid row FontWeights to Bold?, but I was unable to get it working.
This is the code that I tried; running it results in an error, as row is null.
Setter bold = new Setter(TextBlock.FontWeightProperty, FontWeights.Bold, null);
DataGridRow row = (DataGridRow)DG_PPC.ItemContainerGenerator.ContainerFromIndex(3);
Style newStyle = new Style(row.GetType());
newStyle.Setters.Add(bold);
row.Style = newStyle;
I would appreciate any help you can give me. Thank you!
XAML code:
<DataGrid x:Name="DG_PPC" HorizontalAlignment="Left" Height="115" Margin="661,-6,0,0"
HeadersVisibility="Column" VerticalAlignment="Top" Width="726.25"
Loaded="DataGrid_PPC_Loaded" RowHeaderWidth="0" AutoGenerateColumns="False"
CanUserSortColumns="False" CanUserReorderColumns="False" FontSize="12" IsReadOnly="True">
I found myself another way to do it, which is compatible with my code. Here's the solution, in case someone will be needing something similar.
APP.XML:
<Application.Resources>
<local:FontWeightConverter x:Key="FontWeightConverter"/>
</Application.Resources>
XAML:
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="FontWeight" Value="{Binding RelativeSource={RelativeSource Self},
Path=Item.XYZ, Converter={StaticResource FontWeightConverter}}"/>
</Style>
</DataGrid.RowStyle>
Code:
class FontWeightConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string name = (string)value;
if (name.Equals("Δ"))
return FontWeights.Bold;
else
return FontWeights.Normal;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I have ran into a issue with the converters... They are not triggering once the bound collection is updated although they trigger when the collection is first populated. I would like to have them fire whenever there is a change in the collection.
So far I have built a simple converter:
public class TableConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
VM.Measurement t = ((VM.Measurement)((TextBlock)value).DataContext);
if (t.Delta != null)
{
if (Math.Abs((double)t.Delta) < t.Tol)
return "Green";
else
return "Red";
}
else
return "Red";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
which is linked to a style
<conv:TableConverter x:Key="styleConvStr"/>
<Style x:Key="CellStyleSelectorTol" TargetType="syncfusion:GridCell">
<Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self}, Path=Content, Converter={StaticResource styleConvStr}}" />
</Style>
Which is used in this DataGrid
<syncfusion:SfDataGrid x:Name="CheckGrid" BorderBrush="White" Grid.Row="1" Grid.Column="1" AllowEditing="True" ItemsSource="{Binding ChecksList, Mode=TwoWay}" Background="White" SnapsToDevicePixels="False"
ColumnSizer="None" AllowResizingColumns="False" AllowTriStateSorting="True" AllowDraggingColumns="False" CurrentCellEndEdit="CheckGrid_CurrentCellEndEdit" AutoGenerateColumns="False"
NavigationMode="Cell" HeaderRowHeight="30" RowHeight="21" GridPasteOption="None" Margin="20 10 10 10" AllowGrouping="True" SelectedItem="{Binding SelectedLine, Mode=TwoWay}"
SelectionUnit="Row" SelectionMode="Single" RowSelectionBrush="#CBACCB" VirtualizingPanel.IsVirtualizing="True" Visibility="Visible">
<syncfusion:GridTextColumn Width="100" ColumnSizer="SizeToCells" AllowEditing="True" MappingName="Measured" CellStyle="{StaticResource CellStyleSelectorTol}" HeaderText="Measured" TextAlignment="Center" AllowFiltering="False" FilterBehavior="StringTyped"/>
The VM contains an Observable Collection which implements NotifyPropertyChanged all the way down to the Measurement Class. The properties fire up nicely so it is not a binding issue.
private ObservableCollection<Measurement> _checkList = new ObservableCollection<Measurement>();
public ObservableCollection<Measurement> ChecksList
{
get
{
return _checkList;
}
set
{
_checkList = value;
NotifyPropertyChanged();
}
}
Any help with this would be greatly appreciated.
Thanks
EDIT:
Here is the code that updates the collection. Apologies for it being quite messy. Lineitem is the selected line for which Measured and Delta are updated. These are properly displayed in the grid once modified.
public void NewMeasurement(VM.Measurement measurementShell)
{
using (VMEntity DB = new VMEntity())
{
var Check = CheckSets.Where(x => x.ID == SelectedLine.ID).First();
if (Check.Measurement == null)
{
Check.Measurement = measurementShell.Index;
var Lineitem = ChecksList.Where(x => x.ID == SelectedLine.ID).First();
var measurement = DB.Measurements.Where(x => x.Index == Check.Measurement).First();
Lineitem.Measured = (double)measurement.measurement1;
Lineitem.Delta = Lineitem.Measured - Lineitem.Target;
OK, it looks like the problem is that you are changing properties of the cell content item (LineItem, in the NewMeasurement() method), but it's still the same object, so the cell's content doesn't change. The cell's Content is the source for the binding. If that doesn't change, the binding won't wake up and update the target. You're raising PropertyChanged, but this particular binding has no way of knowing you want it to listen to this object for those property changes. Easy enough fix: We'll start telling it exactly what to listen for.
Fortunately the solution means simplifying some of your code. Passing a UI control into a value converter is exotic and not necessary.
What you care about in the converter is Measurement.Delta and Measurement.Tol. When either one changes, the Binding should update its target. You don't want to do that in a clever way. You just want a Binding for each one. That's a Binding's job.
So tell the Binding that you care about those properties, and rewrite the converter to accept both of them as parameters.
<Style x:Key="CellStyleSelectorTol" TargetType="syncfusion:GridCell">
<Setter
Property="Background"
>
<Setter.Value>
<MultiBinding Converter="{StaticResource styleConvStr}">
<Binding Path="Delta" />
<Binding Path="Tol" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
Converter:
public class TableConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
// I'm inferring that Measurement.Delta is Nullable<double>; if that's
// not the case, change accordingly. Is it Object instead?
double? delta = (double?)values[0];
double tol = (double)values[1];
if (delta.HasValue && Math.Abs(delta.Value) < tol)
{
return "Green";
}
return "Red";
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I have a WPF App that has (so far) 2 modes of display, regularmode and widgetmode.
I am using Prism 6 with MVVM design pattern.
MainWindowViewModel knows the mode of display.
ToolBarView has, as expected, a toolbar of buttons and the buttons shall be dynamically changed to different images depending on the mode of the view. If the mode is WidgetMode, it switches to the image with an identical name but with an '_w' added. So instead of "image.png", it's "image_w.png".
What I'd like to do is create a string in ToolBarView that is updated to either String.Empty or to "_w", depending on the mode. I'd also like the image root folder to be a global string, rather than a hardcoded string, so I have defined that in app.xaml.
<Application.Resources>
<sys:String x:Key="ImageURIRoot">/MyApp;component/media/images/</sys:String>
</Application.Resources>
Then in my toolbarview (a usercontrol), I did this:
<UserControl.Resources>
<converters:StringToSourceConverter x:Key="strToSrcConvert"/>
<sys:String x:Key="BtnImgSuffix">_w</sys:String>
.
.
.
</UserControl.Resources>
Note that the string is hardcoded; eventually, I will change it dynamically based off the windowmode.
I then put the Buttons in a Listbox
<ListBoxItem Style="{StaticResource MainButton_Container}">
<Button Command="{Binding ButtonActionDelegateCommand}" Style="{StaticResource Main_Button}">
<Image Source="{Binding Source={StaticResource ImageURIRoot}, Converter={StaticResource strToSrcConvert}, ConverterParameter='{}{0}button.png'}" />
</Button>
</ListBoxItem>
Converter code:
public class StringToSourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (parameter is string)
{
return string.Format(parameter.ToString(), value);
}
return null;
}
public object ConvertBack(object value, Type targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
So that works. But what I want is to have the ConverterParameter equal "{}{0}button{1}.png", where {0} is the URI Root and {1} is the suffix. But I can't figure out how to do it. I know it's simple, but I can't put my finger on it!
Please help!
Figured it out and it was through multibinding. The way I did it was create a converter that inherits from IMultiValueConverter. Its "Convert" method looks like this:
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
ImageSourceConverter conv = new ImageSourceConverter();
int suffixPos = ((String)parameter).Length - 4;
var returnValue = ((String)parameter).Insert(suffixPos, values[1].ToString());
returnValue = Path.Combine(values[0].ToString(), returnValue);
ImageSource imgsrc = conv.ConvertFromString(returnValue) as ImageSource;
return imgsrc;
}
The xaml looks like this:
<Image Height="30" Width="40" diag:PresentationTraceSources.TraceLevel="High">
<Image.Source>
<MultiBinding Converter="{StaticResource stringsToSrcConvert}" ConverterParameter="buttonImg.png">
<Binding Source="{StaticResource ImageURIRoot}"/>
<Binding Source="{StaticResource BtnImgSuffix}"/>
</MultiBinding>
</Image.Source>
</Image>
Also, had to modify the URIRoot
<Application.Resources>
<sys:String x:Key="ImageURIRoot">pack://application:,,,/MyApp;component/media/images/</sys:String>
</Application.Resources>
Thanks, Clemens!
HI to all I facing one problem which is that my IValueConverter cannot get the new image:
Is my code correct?
XAML FILE:
<Window.Background>
<!--Budget Categories-->
<DataTemplate x:Key="CategoriesName">
<Border BorderBrush="#FF000000" BorderThickness="1,1,0,1" Margin="-6,-2,-6,-2">
<StackPanel Margin="6,2,6,2">
<TextBlock Text="{Binding Path=CategoriesName}"/>
</StackPanel>
</Border>
</DataTemplate>
<DataTemplate x:Key="CategoriesType">
<Border BorderBrush="#FF000000" BorderThickness="1,1,0,1" Margin="-6,-2,-6,-2">
<!--<StackPanel Margin="6,2,6,2">
<TextBlock Text="{Binding Path=CategoriesType}"/>
</StackPanel>-->
<StackPanel Margin="6,2,6,2">
<Image Source="{Binding Path=CategoriesType,Converter={StaticResource typeToImageConverter}}" Width="16" Height="16" Margin="3,0"/>
<TextBlock Text="{Binding Path=CategoriesType}"/>
</StackPanel>
</Border>
</DataTemplate>
<DataTemplate x:Key="CategoriesExpect">
<Border BorderBrush="#FF000000" BorderThickness="1,1,0,1" Margin="-6,-2,-6,-2">
<StackPanel Margin="6,2,6,2">
<TextBlock Text="{Binding Path=CategoriesTotalExpect}"/>
</StackPanel>
</Border>
</DataTemplate>
<DataTemplate x:Key="CategoriesActual">
<Border BorderBrush="#FF000000" BorderThickness="1,1,1,1" Margin="-6,-2,-6,-2">
<StackPanel Margin="6,2,6,2">
<TextBlock Text="{Binding Path=CategoriesTotalActual}"/>
</StackPanel>
</Border>
</DataTemplate>
<!--Budget Categories-->
</Window.Background>
<ListView Height="320" HorizontalAlignment="Left" Margin="12,154,0,0" Name="CategoriesListView" VerticalAlignment="Top" Width="316" ItemsSource="{Binding}" ItemContainerStyle="{DynamicResource MyItemContainerStyle}">
<ListView.View>
<GridView>
<GridViewColumn Header="Categories" Width="150" CellTemplate="{DynamicResource CategoriesName}" />
<GridViewColumn Header="Types" Width="40" CellTemplate="{DynamicResource CategoriesType}"/>
<GridViewColumn Header="Expect" Width="60" CellTemplate="{DynamicResource CategoriesExpect}"/>
<GridViewColumn Header="Actual" Width="60" CellTemplate="{DynamicResource CategoriesActual}"/>
</GridView>
</ListView.View>
</ListView>
This is my TypeToImageConverter.cs:
public class TypeToImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string str = (string)value;
if (str == "income")
return new BitmapImage(new Uri("pack://application:,,,/images/add.png"));
if (str == "Expenses")
{
return new BitmapImage(new Uri(#"pack://application:,,,/HouseWivesSavior;component/images/add.png"));
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
I found the solution for my answer which is the format of the string. Which causing me to unavailable to retrieve the image with few hours of troubleshooting & debugging. I finally found out the solution :)
I solve it by like this:In my converter.cs
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string str = (string)value;
string newString = str.TrimEnd();//Newly added compared with the old version
if (newString == "income")
return new BitmapImage(new Uri("pack://application:,,,/images/add.png"));
if (newString == "Expenses")
{
//return new BitmapImage(new Uri(#"pack://application:,,,/HouseWivesSavior;component/images/add.png"));
return new BitmapImage(new Uri("pack://application:,,,/images/edit.png"));
}
return null;
}
From referring the above that you can see that I added this code:
"string newString = str.TrimEnd();"
Is because I don't want extra white space at the end of the string. As during insert into the database that my code is look like this:
if (IncomeButton.IsChecked == true) {
CategoryType = IncomeButton.Content.ToString();
}else{
CategoryType = ExpensesButton.Content.ToString();
}
During runtime, I found out that why the value look strange in the format of "Expenses " instead of "Expenses"... Therefore I tried with trim of the end part see how & Bingo. I got it working like a charm.
I refered this video to out that how to trace the value:
http://www.youtube.com/watch?v=evO3_xutDYI
Thank you all guys for answering my question & sorry for wasting your time & effort to solve my question :) And special thank to #Blam which answered me :)
Good luck to all of you & have a nice day.
I have a datepicker in my C# 4.0 (WPF) application and I would like to change the format of the date that is visible in the textBox to yyyy/MM/dd. Now I see the format dd/MM/yyyy.
In my axml of the datePicker I have this code:
<DatePicker Height="25" HorizontalAlignment="Left" Margin="5,36,0,0" Name="dtpStartDate"
SelectedDate="{Binding StartDateSelectedDate}" VerticalAlignment="Top" Width="115">
<DatePicker.Resources>
<Style TargetType="{x:Type DatePickerTextBox}">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<TextBox x:Name="PART_TextBox"
Text="{Binding Path=SelectedDate, RelativeSource={RelativeSource AncestorType={x:Type DatePicker}}, StringFormat={}{0:yyyy/MM/dd}}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DatePicker.Resources>
</DatePicker>
This seems in a first time that all works fine, I can see the date in the format that I want, and I can change the date manually or using the calendar, and in both ways the date that arrives to the viewModel is the correct.
But I have a problem, because I would like to detect that if the date is empty, in my view model control this case. But If I clear the datepicker, in my view model arrives the last correct date, so I can't check if the date is empty or not.
So how can I modify the format of the date in the date picker and control if the date is empty/null or not?
Thanks.
Daimroc.
you can try the following solution.
First create the following converter :
public class StringToDateTimeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
{
return null;
}
return ((DateTime)value).ToString(parameter as string, CultureInfo.InvariantCulture);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (string.IsNullOrEmpty(value as string))
{
return null;
}
try
{
DateTime dt = DateTime.ParseExact(value as string, parameter as string, CultureInfo.InvariantCulture);
return dt as DateTime?;
}
catch (Exception)
{
return null;
}
}
}
Then in the xaml, you will have to create an instance of the converter and use it in the textbox of the DatePicker
<Window x:Class="TestDatePicker.MainWindow"
...
xmlns:converters="clr-namespace:TestDatePicker"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
...
<converters:StringToDateTimeConverter x:Key="StringToDateTimeConverter" />
</Window.Resources>
<Grid DataContext="{StaticResource MainWindowVM}">
...
<DatePicker Height="25" HorizontalAlignment="Left" Margin="5,36,0,0" Name="dtpStartDate"
SelectedDate="{Binding StartDateSelectedDate}" VerticalAlignment="Top" Width="115">
<DatePicker.Resources>
<Style TargetType="{x:Type DatePickerTextBox}">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<TextBox x:Name="PART_TextBox"
Text="{Binding Path=SelectedDate, RelativeSource={RelativeSource AncestorType={x:Type DatePicker}}, Converter={StaticResource StringToDateTimeConverter}, ConverterParameter=yyyy/MM/dd}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DatePicker.Resources>
</DatePicker>
...
</Grid>
Finally, in the viewmodel, the property must be of type DateTime? (i.e a nullable DateTime).
private DateTime? _startDateSelectedDate;
public DateTime? StartDateSelectedDate
{
get { return _startDateSelectedDate; }
set
{
if (_startDateSelectedDate != value)
{
_startDateSelectedDate = value;
RaisePropertyChanged(() => this.StartDateSelectedDate);
}
}
}
I hope this will help you
Regards
Claude
defaultly the DateTimerPicker does not support null values.
Maybe this post from MSDN with the same topic can help you.
There you will find other ideas how to implement it or some code project for nullable date time picker.