I have a unique situation. In one class, I have an inner class that acts as pretty much just a "display" class. In the outer class there is a method called GetDisplayObject that returns a type of the inner class.
I'm trying to bind to a datagrid with the outer class, but by using a converter I'd like to get the correct display. This way I won't have to change a bunch of code in our application and just add a few lines in a couple .xaml files.
I made a little test app that pretty much sums up my problem at it's most basic level. Ideally I'd like to solve the problem by using a converter and returning values only as a display, that way when i'm using the SelectedItem I won't have to change a ton of code that is depending on that certain type(In this case would be the DataObject type).
So here is the objects i'm stuck dealing with
namespace TestApp
{
public class DataObject
{
public class DataObjectDisplay
{
public string ObjectDisplay { get; set; }
}
// props
public int Id { get; set; }
public object Object1 { get; set; }
public object Object2 { get; set; }
// method for getting the display
public DataObjectDisplay GetDisplayObject()
{
DataObjectDisplay display = new DataObjectDisplay();
// logic for determining which object should be displayed
if(Object1 == null)
{
display.ObjectDisplay = "Object1";
}
else
{
display.ObjectDisplay = "Object2";
}
return display;
}
}
}
Here is the Code Behind of my xaml
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
namespace TestApp
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
this.DataContext = this;
InitializeComponent();
this.DataObjectCollection = new ObservableCollection<DataObject>();
this.DataObjectCollection.Add(new DataObject() { Id = 1, Object1 = "this", Object2 = "that" });
this.DataObjectCollection.Add(new DataObject() { Id = 1, Object2 = "that" });
this.SelectedItem = new DataObject();
}
private ObservableCollection<DataObject> dataObjectCollection;
private DataObject selectedItem;
public ObservableCollection<DataObject> DataObjectCollection
{
get { return this.dataObjectCollection; }
set
{
dataObjectCollection = value;
OnNotifyPropertyChanged("DataObjectCollection");
}
}
public DataObject SelectedItem
{
get { return this.selectedItem; }
set
{
selectedItem = value;
OnNotifyPropertyChanged("SelectedItem");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnNotifyPropertyChanged(string property = "")
{
if(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
}
Here is the xaml(This is something like what i'd want to do, using the itemtemplate or something similar, and then a converter to call this GetDisplay function)
<Window x:Class="TestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestApp"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:DataObjectToDisplayDataObjectConverter x:Key="ToDisplayConverter"/>
</Window.Resources>
<StackPanel>
<DataGrid ItemsSource="{Binding DataObjectCollection}" SelectedItem="{Binding SelectedItem}" MinHeight="200">
<DataGrid.ItemTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding Converter={StaticResource ToDisplayConverter}}"/>
</DataTemplate>
</DataGrid.ItemTemplate>
</DataGrid>
</StackPanel>
</Window>
And Finally the converter
using System;
using System.Globalization;
using System.Windows.Data;
namespace TestApp
{
public class DataObjectToDisplayDataObjectConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null && value.GetType() == typeof(DataObject))
{
DataObject dataObj = (DataObject)value;
dataObj.GetDisplayObject();
return dataObj;
}
return "Invalid Value";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
I am open to suggestions, but this is a small example. In our actual application changing one thing will most likely cascade into a huge ordeal.
If I were you I would have change close coupling of view with ViewModel, Like creating new MainWindowViewModel class & having all properties in it.
Another thing I see GetDisplayObject method, what's the need of calling such a method from converter.
You can re-factor this code & put in the converter something like this.
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
DataObject dataObj = value as DataObject;
if (value == null)
{
return "Invalid Value";
}
if (dataObj.Object1 == null)
{
return "Object1";
}
return "Object2";
}
Luckily since it was a matter of if one object was null and it's related strings were empty, I was able to use Priority Binding with a converter to return DependencyProperty.UnsetValue and force it to use the next binding. I think this was the best solution for the situation.
So the xaml ended up looking like this.
<DataGrid ItemsSource="{Binding DataObjectCollection}" SelectedItem="{Binding SelectedItem}" MinHeight="200">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<PriorityBinding>
<Binding Path="Object1" Converter="{StaticResource EmptyStringToDependencyPropertyUnset}"/>
<Binding Path="Object2"/>
</PriorityBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
And the Converter ended up like this
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value == null || value as string == string.Empty)
{
return DependencyProperty.UnsetValue;
}
return value;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.