Hide a Column Using Data Annotations in WPF - wpf

I have a grid in WPF, auto-generating columns. How can I dynamically hide columns using data annotations?
I thought of having a property in my model to specify whether the column is visible, but I'm not sure how to do it.
My model, bound to the grid:
public class Template
{
public string County { get; set; }
public string Operator { get; set; }
public string Field { get; set; }
}

Here is a sample which uses attributes to hide columns. It uses an attached property to handle the AutoGeneratingColumn event.
HideColumnIfAutoGenerated.cs - Attribute
namespace AutoHideColumn
{
public class HideColumnIfAutoGenerated : System.Attribute
{
public HideColumnIfAutoGenerated()
{
}
}
}
DataGridExtension.cs - Attached Property
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace AutoHideColumn
{
public static class DataGridExtension
{
public static readonly DependencyProperty HideAnnotatedColumnsProperty = DependencyProperty.RegisterAttached(
"HideAnnotatedColumns",
typeof(bool),
typeof(DataGridExtension),
new UIPropertyMetadata(false, OnHideAnnotatedColumns));
public static bool GetHideAnnotatedColumns(DependencyObject d)
{
return (bool)d.GetValue(HideAnnotatedColumnsProperty);
}
public static void SetHideAnnotatedColumns(DependencyObject d, bool value)
{
d.SetValue(HideAnnotatedColumnsProperty, value);
}
private static void OnHideAnnotatedColumns(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
bool hideAnnotatedColumns = (bool)e.NewValue;
DataGrid dataGrid = d as DataGrid;
if (hideAnnotatedColumns)
{
dataGrid.AutoGeneratingColumn += dataGrid_AutoGeneratingColumn;
}
else
{
dataGrid.AutoGeneratingColumn -= dataGrid_AutoGeneratingColumn;
}
}
private static void dataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
PropertyDescriptor propertyDescriptor = e.PropertyDescriptor as PropertyDescriptor;
if (propertyDescriptor != null)
{
foreach (var item in propertyDescriptor.Attributes)
{
if (item.GetType() == typeof(HideColumnIfAutoGenerated))
{
e.Cancel = true;
}
}
}
}
}
}
XAML
<Window x:Class="AutoHideColumn.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AutoHideColumn"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<DataGrid Name="dg" local:DataGridExtension.HideAnnotatedColumns="True">
</DataGrid>
<DataGrid Grid.Row="1" Name="dg1">
</DataGrid>
</Grid>
</Window>
CodeBehind
using System.Collections.Generic;
using System.Windows;
namespace AutoHideColumn
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.dg.ItemsSource = new List<Customer>();
this.dg1.ItemsSource = new List<Customer>();
}
}
public class Customer
{
[HideColumnIfAutoGenerated()]
public int ID { get; set; }
public string Name { get; set; }
}
}

Try this
public partial class MainWindow : Window
{
private List<string> visibleColumns;
public MainWindow()
{
InitializeComponent();
InitializeList();
visibleColumns = GetVisibleColumns();
dg.AutoGeneratingColumn += dg_AutoGeneratingColumn;
dg.ItemsSource = Templates;
}
void dg_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
if(!visibleColumns.Contains(e.Column.Header.ToString()))
e.Column.Visibility=Visibility.Collapsed;
}
List<string> GetVisibleColumns()
{
return typeof(Template).GetProperties()
.Where(p =>
p.GetCustomAttributes(typeof(Visible), true)
.Where(ca => ((Visible)ca).IsVisible).Any()
).Select(s => s.Name).ToList();
}
private void InitializeList()
{
Templates = new List<Template>();
Templates.Add(new Template { County = "abc", Operator = "123", Field = "xyz" });
Templates.Add(new Template { County = "abc", Operator = "123", Field = "xyz" });
Templates.Add(new Template { County = "abc", Operator = "123", Field = "xyz" });
Templates.Add(new Template { County = "abc", Operator = "123", Field = "xyz" });
}
public List<Template> Templates { get; set; }
}
>Template Class
public class Template
{
[Visible(false)]
public string County { get; set; }
[Visible(true)]
public string Operator { get; set; }
[Visible(true)]
public string Field { get; set; }
}
>Visible Attribute
public class Visible : Attribute
{
public Visible(bool isVisible)
{
IsVisible = isVisible;
}
public bool IsVisible { get; set; }
}
>xaml
<Grid>
<DataGrid AutoGenerateColumns="True" x:Name="dg"/>
</Grid>

this would be by far the most simplistic workaround which comes close to data annotation: omit the getter and setter.
public class Template
{
public string County { get; set; }
public string Operator { get; set; }
public string Field; //This is now a field and not a property-> invisible in datadrid
}

Attributes cannot be changed at run time hence you cannot dynamically hide columns using data annotations. But it is possible to dynamically hide columns. Here is an example which demonstrates it.
XAML
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<DataGrid ItemsSource="{Binding AutoGenerateColumnDetails}" CanUserAddRows="False" CanUserDeleteRows="False">
</DataGrid>
<Button Grid.Row="1" Content="Refresh" Click="Button_Click" HorizontalAlignment="Left" Margin="5"/>
<DataGrid Name="dg" Grid.Row="2" ItemsSource="{Binding TemplateList}" AutoGeneratingColumn="dg_AutoGeneratingColumn">
</DataGrid>
</Grid>
Code behind
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
namespace AutoHideDGColumn
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ViewModel _ViewModel = null;
public MainWindow()
{
InitializeComponent();
_ViewModel = new ViewModel();
this.DataContext = _ViewModel;
}
private void dg_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
if (_ViewModel.AutoGenerateColumnDetails.Where(d => d.HideColumn == true).Select(d => d.PropertyName).ToList().Contains(e.PropertyName))
e.Cancel = true;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// Reset to trigger AutoGeneratingColumn event
this.dg.AutoGenerateColumns = false;
this.dg.AutoGenerateColumns = true;
}
}
public class ViewModel
{
private List<Template> _TemplateList;
public List<Template> TemplateList
{
get { return _TemplateList; }
set { _TemplateList = value; }
}
private List<AutoGenerateColumnDetail> _AutoGenerateColumnDetails;
public List<AutoGenerateColumnDetail> AutoGenerateColumnDetails
{
get { return _AutoGenerateColumnDetails; }
set { _AutoGenerateColumnDetails = value; }
}
public ViewModel()
{
AutoGenerateColumnDetails = typeof(Template).GetProperties().Select(p => new AutoGenerateColumnDetail() { PropertyName = p.Name }).ToList();
TemplateList = new List<Template>()
{
new Template() { County = "Count1", Field = "Field1", Operator = "Operator1"},
new Template() { County = "Count2", Field = "Field2", Operator = "Operator2"},
new Template() { County = "Count3", Field = "Field2", Operator = "Operator3"},
};
}
}
public class Template
{
public string County { get; set; }
public string Operator { get; set; }
public string Field { get; set; }
}
public class AutoGenerateColumnDetail
{
public string PropertyName { get; set; }
public bool HideColumn { get; set; }
}
}

Related

How to bind a control value to another source

I have a ListView which is populated with a collection called Files(ObservableCollection FileViewModel ), also I have another SelectedFiles(List Guid ) which hold the selected files id in it, how can I bind this to the UI to show the selected files with checkbox control.
Xaml:
<ListView Grid.Column="0" Grid.Row="2" Name="lstSourceFiles" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<CheckBox></CheckBox>
<TextBlock Text="{Binding Name}"></TextBlock>
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code:
public List<Guid> SelectedSourceFiles { get; set; }
public ObservableCollection<FileViewModel> Files { get; set; }
public class FileViewModel
{
public Guid Id { get; set; }
public string Name { get; set; }
}
public partial class MainWindow : Window
{
public List<Guid> SelectedSourceFiles { get; set; }
public MainWindow()
{
AddHandler(TreeViewItem.SelectedEvent, new RoutedEventHandler(TreeItemSelected), true);
}
private void TreeItemSelected(object sender, RoutedEventArgs e)
{
var item = e.OriginalSource as TreeViewItem;
if (item == null)
{ return; }
var folder = item.DataContext as FolderViewModel;
if (folder == null)
{ return; }
if (!folder.IsFilesLoaded)
{
FileManager.LoadFiles(folder);
}
lstSourceFiles.ItemsSource = folder.Files;
}
}
The easiest way would be to add an "IsSelected" property to the view model:
public class FileViewModel
{
public Guid Id { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
Loop through and set the property:
foreach (var file in folder.Files)
file.IsSelected = (SelectedSourceFiles.Contains(file.Guid);
And then of course bind to it:
<CheckBox IsChecked="{Binding IsSelected}" />
An alternate to the above would be to bind to the GUID and use IValueConverter that checks against the the selected list.

resolve specific dependency in unity DI/IOC

While exploring DI/IOC with Unity with WPF, I came across a question and need your feedback. Please consider the following scenario...
================================================================
public interface IDataServices
{
string GetData();
}
================================================================
public class CopyTextDataServices : IDataServices
{
public string GetData()
{
return "copy text from CopyTextDataServices";
}
}
================================================================
public class TextDataServices : IDataServices
{
public string GetData()
{
return "I am injected by setter property injection";
}
}
================================================================
public interface ITextViewModel
{
string LabelContnet { get; set; }
}
================================================================
public class TextViewModel : ITextViewModel
{
public TextViewModel()
{
LabelContnet = "This is from view model";
}
public string LabelContnet { get; set; }
}
================================================================
public partial class MainWindow : Window
{
public MainWindow(ITextViewModel textViewModel)
{
InitializeComponent();
Loaded += MainWindow_Loaded;
DataContext = textViewModel;
}
[Dependency]
public IDataServices Services { get; set; }
containing the event data.</param>
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
LabelLeft.Content = Services.GetData();
}
}
================================================================
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
IUnityContainer container = new UnityContainer();
container.RegisterType<IDataServices, TextDataServices>();
container.RegisterType<IDataServices, CopyTextDataServices>();
container.RegisterType<ITextViewModel, TextViewModel>();
var window = container.Resolve<MainWindow>();
window.Show();
}
}
================================================================
<Window x:Class="TestAppWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" FontSize="20">
<StackPanel>
<Label Content="{Binding Path=LabelContnet,FallbackValue=Left}" HorizontalAlignment="Left" Name="LabelLeft" />
<Label Content="{Binding Path=LabelContnet,FallbackValue=Right}" HorizontalAlignment="Left" Name="LabelRight" />
</StackPanel>
</Window>
===================================================================
Now the result of this appears in the labels is
copy text from CopyTextDataServices
This is from view model
But I want to know if I want to get data from TextDataServices, how can I do that?
The problem is in this line:
container.RegisterType<IDataServices, TextDataServices>();
// This overwrites the previous mapping.
// All dependencies to IDataServices will use CopyTextDataServices.
container.RegisterType<IDataServices, CopyTextDataServices>();
If you want to have both IDataServices, you'll need to register one or both as named instances.
container.RegisterType<IDataServices, TextDataServices>("TextDataServicesName");
container.RegisterType<IDataServices, CopyTextDataServices>("CopyTextDataServicesName");
In your control:
[Dependency("TextDataServicesName")]
public IDataServices Services { get; set; }

SelectedItem on ComboBox

There is a ComboBox in the application which is bound to a collection of items. There are cases that user can select an item from the ComboBox but the selected item might not be ready yet so the ComboBox selected item must get back to the previous selected item (or some other item in the collection), but in the current application ComboBox always shows the selected item from the user instead of retrieving the valid item after setting it back and calling notify property change.
The flowing is a simplified code of which shows the problem.
public partial class MainWindow : Window, INotifyPropertyChanged
{
private List<Customer> _Customers = new List<Customer>();
public List<string> CustomerNames
{
get
{
var list = new List<string>();
foreach (var c in _Customers)
{
list.Add(c.Name);
}
return list; ;
}
}
public string CustomerName
{
get
{
var customer = _Customers.Where(c => c.IsReady).FirstOrDefault();
return customer.Name;
}
set
{
NotifyPropertyChanged("CustomerName");
}
}
public MainWindow()
{
SetupCustomers();
InitializeComponent();
this.DataContext = this;
}
private void SetupCustomers()
{
_Customers.Add(new Customer("c1", true));
_Customers.Add(new Customer("c2", false));
_Customers.Add(new Customer("c3", false));
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Customer
{
public Customer(string name, bool isReady)
{
this.Name = name;
this.IsReady = isReady;
}
public bool IsReady { get; set; }
public string Name { get; set; }
public override bool Equals(object obj)
{
return base.Equals(obj);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
<Window x:Class="TryComboboxReset.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ComboBox Width="100"
Height="25"
ItemsSource="{Binding Path=CustomerNames, Mode=OneWay}"
SelectedItem="{Binding Path=CustomerName, Mode=TwoWay}"/>
</Grid>
The problem was UI thread, I used dispatcher to fix this problem
public partial class MainWindow : Window, INotifyPropertyChanged
{
private ObservableCollection<Customer> _Customers =
new ObservableCollection<Customer>();
public ObservableCollection<Customer> CustomerNames
{
get
{
return _Customers;
}
}
public Customer CustomerName
{
get
{
return _Customers.Where(c => c.IsReady == true).FirstOrDefault();
}
set
{
// Delay the revert
Application.Current.Dispatcher.BeginInvoke(
new Action(() => NotifyPropertyChanged("CustomerName")), DispatcherPriority.ContextIdle, null);
}
}
public MainWindow()
{
SetupCustomers();
InitializeComponent();
this.DataContext = this;
}
private void SetupCustomers()
{
_Customers.Add(new Customer("c1", true));
_Customers.Add(new Customer("c2", false));
_Customers.Add(new Customer("c3", false));
CustomerName = _Customers.Where(c => c.IsReady == true).FirstOrDefault();
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Customer
{
public Customer(string name, bool isReady)
{
this.Name = name;
this.IsReady = isReady;
}
public bool IsReady { get; set; }
public string Name { get; set; }
}
<ComboBox Width="400"
Height="25"
ItemsSource="{Binding Path=CustomerNames}"
SelectedValue="{Binding CustomerName,Mode=TwoWay}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
You aren't actually setting the value of the selected customer name in your setter, and your getter is always going to return the first "ready" customer name it finds...
If I'm understanding the problem correctly, you need to be doing something more along these lines:
private string _customerName = null;
public string CustomerName
{
get
{
if(_customerName == null)
{
_customerName = _Customers.Where(c => c.IsReady).FirstOrDefault().Name;
}
return _customerName;
}
set
{
_customerName = value;
NotifyPropertyChanged("CustomerName");
}
}

Dynamic WPF datagrid with usercontrols

I've been at this for several times during the last couple of months, but I can't figure out how to do it.
I have a DataGrid that should show a clickable usercontrol in all columns except the first one, which should be a regular textcolumn without editing possibilities. The problem is that the number of columns has to be dynamic, there can be 2 to n ones.
Since I don't even know where to start I don't have any sample code.
If anyone could help getting me on track, I would be very grateful. The solution doesn't have to be proper MVVM or extremely fancy, it just has to work.
UPDATE 1 - A self-containing c# version.
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.Specialized;
using System.Globalization;
namespace DynamicColumns
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Loaded +=
(o, e) =>
{
this.PopulateItemsSource();
};
}
private void PopulateItemsSource()
{
int months = Math.Max(new Random().Next(12), 1);
this.d.ItemsSource =
new string[]
{
"John",
"Paul",
"Peter"
}.Select(t =>
MonthlyPerformance.CreateDummy(t, months)).ToList();
}
private void RePopulateButton_Click(object sender, RoutedEventArgs e)
{
this.PopulateItemsSource();
}
}
#region "Interfaces - must be in the shared between Objects & UI"
public interface IDynamicPropertiesObject
{
Dictionary<string, string> Properties { get; }
}
#endregion
#region "Objects"
public class MonthlyPerformance : IDynamicPropertiesObject
{
public string PerformerName
{
get;
set;
}
public Dictionary<string, string> Properties
{
get;
private set;
}
public static MonthlyPerformance CreateDummy(string performerName,
int months)
{
if (months < 1 || months > 12)
{
throw new ArgumentException(months.ToString());
}
Random random = new Random();
return new MonthlyPerformance()
{
PerformerName =
performerName,
Properties =
Enumerable.Range(1, months).ToDictionary(k => new DateTime(1, k, 1).ToString("MMM"), v => random.Next(100).ToString())
};
}
}
#endregion
#region "UI"
internal class DynamicPropertyValueConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
IDynamicPropertiesObject o = value as IDynamicPropertiesObject;
if (o != null)
{
return o.Properties[parameter.ToString()];
}
return Binding.DoNothing;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class ExtendedDataGrid: DataGrid
{
public static readonly DependencyProperty IsDynamicColumnProperty =
DependencyProperty.RegisterAttached("IsDynamicColumn",
typeof(Boolean),
typeof(ExtendedDataGrid),
new PropertyMetadata(false));
private DynamicPropertyValueConverter converter = null;
public ExtendedDataGrid()
{
this.EnableColumnVirtualization = true;
this.EnableRowVirtualization = true;
this.AutoGenerateColumns = false;
}
private DynamicPropertyValueConverter Converter
{
get
{
if (this.converter == null)
{
converter = new DynamicPropertyValueConverter();
}
return this.converter;
}
}
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
{
base.OnItemsChanged(e);
this.ReGenerateColums();
}
private bool TryGetDynamicColumn(out DataGridColumn column)
{
column =
this.Columns.FirstOrDefault(t=>(bool)t.GetValue(ExtendedDataGrid.IsDynamicColumnProperty));
return column != null;
}
private void ClearDynamicColumns()
{
DataGridColumn column;
while (this.TryGetDynamicColumn(out column))
{
this.Columns.Remove(column);
}
}
private void ReGenerateColums()
{
this.ClearDynamicColumns();
if (this.Items.Count > 0)
{
IDynamicPropertiesObject o =
this.Items[0] as IDynamicPropertiesObject;
if (o != null)
{
foreach (KeyValuePair<string, string> property
in o.Properties)
{
DataGridTextColumn column =
new DataGridTextColumn()
{
Header = property.Key,
Binding = new Binding()
{
Converter = this.Converter,
ConverterParameter = property.Key
}
};
column.SetValue(ExtendedDataGrid.IsDynamicColumnProperty, true); // so we can remove it, when calling ClearDynamicColumns
this.Columns.Add(column);
}
}
}
}
}
#endregion
}
Markup:
<Window x:Class="DynamicColumns.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DynamicColumns"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button x:Name="RePopulateButton" Grid.Row="0" Click="RePopulateButton_Click">Re-Populate</Button>
<local:ExtendedDataGrid x:Name="d" Grid.Row="1">
<local:ExtendedDataGrid.Columns>
<DataGridTextColumn Width="Auto" Binding="{Binding PerformerName}"/>
</local:ExtendedDataGrid.Columns>
</local:ExtendedDataGrid>
</Grid>
</Window>

Binding to ItemsSource not working until visual element is manually inspected (MVVM)

I have the Xaml which should basically bind a set of ContextualButtons for a selected tab's viewmodel to the ItemsSource property of the ToolBar. For some reason, this binding is not actually occuring unless I use Snoop to inspect the element manually...It seems that the act of snooping the element is somehow requerying the binding somehow.
Does anyone know what I might be doing wrong here? This behavior is the same if I use a Listbox as well, so I know it is something that I am doing incorrectly...but I am not sure what.
SelectedView is a bound property to the selected view from a Xam Tab control.
XAML
<ToolBar DataContext="{Binding SelectedView.ViewModel}"
ItemsSource="{Binding ContextualButtons}" >
<ToolBar.ItemTemplate>
<DataTemplate>
<!-- <Button ToolTip="{Binding Name}"-->
<!-- Command="{Binding Command}">-->
<!-- <Button.Content>-->
<!-- <Image Width="32" Height="32" Source="{Binding ImageSource}"/>-->
<!-- </Button.Content>-->
<!-- </Button>-->
<Button Content="{Binding Name}"/>
</DataTemplate>
</ToolBar.ItemTemplate>
</ToolBar>
Code
public class TestViewModel : BaseViewModel, IBulkToolViewModel
{
public TestViewModel()
{
ContextualButtons = new ObservableCollection<IContextualButton>()
{
new ContextualButton("Test Button",
new DelegateCommand<object>(
o_ => Trace.WriteLine("Called Test Button")), String.Empty)
};
}
public string Key { get; set; }
private ObservableCollection<IContextualButton> _contextualButtons;
public ObservableCollection<IContextualButton> ContextualButtons
{
get { return _contextualButtons; }
set
{
if (_contextualButtons == value) return;
_contextualButtons = value;
//OnPropertyChanged("ContextualButtons");
}
}
}
public partial class TestView : UserControl, IBulkToolView
{
public TestView()
{
InitializeComponent();
}
public IBulkToolViewModel ViewModel { get; set; }
}
public class ContextualButton : IContextualButton
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
public ICommand Command { get; set; }
public string ImageSource { get; set; }
public ContextualButton(string name_, ICommand command_, string imageSource_)
{
Name = name_;
Command = command_;
ImageSource = imageSource_;
}
}
public class BulkToolShellViewModel : BaseViewModel, IBaseToolShellViewModel, IViewModel
{
private IBulkToolView _selectedView;
public IBulkToolView SelectedView
{
get
{
return _selectedView;
}
set
{
if (_selectedView == value) return;
_selectedView = value;
OnPropertyChanged("SelectedView");
}
}
public ObservableCollection<IBulkToolView> Views { get; set; }
public DelegateCommand<object> AddViewCommand { get; private set; }
public DelegateCommand<object> OpenPortfolioCommand { get; private set; }
public DelegateCommand<object> SavePortfolioCommand { get; private set; }
public DelegateCommand<object> GetHelpCommand { get; private set; }
public BulkToolShellViewModel(ObservableCollection<IBulkToolView> views_)
: this()
{
Views = views_;
}
public BulkToolShellViewModel()
{
Views = new ObservableCollection<IBulkToolView>();
AddViewCommand = new DelegateCommand<object>(o_ => Views.Add(new TestView
{
ViewModel = new TestViewModel()
}));
OpenPortfolioCommand = new DelegateCommand<object>(OpenPortfolio);
SavePortfolioCommand = new DelegateCommand<object>(SavePortfolio);
GetHelpCommand = new DelegateCommand<object>(GetHelp);
}
private void GetHelp(object obj_)
{
}
private void SavePortfolio(object obj_)
{
}
private void OpenPortfolio(object obj_)
{
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged()
{
throw new NotImplementedException();
}
public void RaisePropertyChanged(string propertyName)
{
throw new NotImplementedException();
}
public string this[string columnName]
{
get { throw new NotImplementedException(); }
}
public string Error { get; private set; }
public AsyncContext Async { get; private set; }
public XmlLanguage Language { get; private set; }
public string Key { get; set; }
}
Thanks!
Why does BulkToolShellViewModel have its own PropertyChanged event along with RaisePropertyChanged methods that do nothing? Shouldn't it inherit this functionality from BaseViewModel? Perhaps the UI is attaching to BulkToolShellViewModel.PropertyChanged rather than BaseViewModel.PropertyChanged and is never being notified of changes.

Resources