It works when I bind directly to EventsSource but it doesn't when I change the binding to EventsView.
// EventsControl class
private bool Filter(object obj)
{
if (!(obj is Event #event)) return false;
if (string.IsNullOrEmpty(Location)) return true;
return true;
// return #event.Location == Location;
}
public static readonly DependencyProperty EventsSourceProperty = DependencyProperty.Register(
nameof(EventsSource), typeof(ObservableCollection<Event>), typeof(EventsControl), new PropertyMetadata(default(ObservableCollection<Event>), EventsSourceChanged));
public ObservableCollection<Event> EventsSource
{
get => (ObservableCollection<Event>)GetValue(EventsSourceProperty);
set => SetValue(EventsSourceProperty, value);
}
public ICollectionView EventsView { get; set; }
private static void EventsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is EventsControl eventsControl)) return;
var view = new CollectionViewSource { Source = e.NewValue }.View;
view.Filter += eventsControl.Filter;
eventsControl.EventsView = view;
//view.Refresh();
}
What could be wrong with this code?
I don't want to use a default view (
WPF CollectionViewSource Multiple Views? )
I made it a dependency property and it works. Not sure if that's the best way to solve it though.
public static readonly DependencyProperty EventsViewProperty = DependencyProperty.Register(
nameof(EventsView), typeof(ICollectionView), typeof(EventsControl), new PropertyMetadata(default(ICollectionView)));
public ICollectionView EventsView
{
get => (ICollectionView) GetValue(EventsViewProperty);
set => SetValue(EventsViewProperty, value);
}
Related
I'm trying to create a TextBox control that has a "Table of values" and an "Index" as dependency properties, were I can changed the Index property and the TextBox will look for the corresponding Value from the Table.
Here's the code:
public class Record
{
public int Index { get; set; }
public string Value { get; set; }
}
public class IndexedTextBox : TextBox
{
public static readonly DependencyProperty TableProperty = DependencyProperty.Register(nameof(Table),
typeof(IEnumerable<Record>), typeof(IndexedTextBox));
public static readonly DependencyProperty IndexProperty = DependencyProperty.Register(nameof(Index),
typeof(int), typeof(IndexedTextBox), new PropertyMetadata(0, IndexChangedCallback));
private static void IndexChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
IndexedTextBox ctl = d as IndexedTextBox;
int index = (int)e.NewValue;
if (ctl.Table.Any(t => t.Index == index))
ctl.Text = ctl.Table.Where(t => t.Index == index).FirstOrDefault().Value;
else
ctl.Text = "N/A";
}
public IEnumerable<Record> Table
{
get => (IEnumerable<Record>)GetValue(TableProperty);
set => SetValue(TableProperty, value);
}
public int Index {
get => (int)GetValue(IndexProperty);
set => SetValue(IndexProperty, value);
}
}
And the XAML code is something like this:
<local:IndexedTextBox Table="{Binding ViewModelTable}" Index="1"/>
Sometimes is works, other times it won't.
I noticed that the 2 properties (Table and Index) are being initialized in random order, and whenever the Index is loaded before the Table the control won't work as expected.
Is there a workaround to that? Can we control the order of the Initialization or there any other thing I should be doing.
I'd greatly appreciate a feedback
Thanks
whenever the Index is loaded before the Table the control won't work as expected ...
So change the implementation to make it work by for example invoking the callback for both properties and check the state of the control before doing anything, e.g.:
public class IndexedTextBox : TextBox
{
public static readonly DependencyProperty TableProperty = DependencyProperty.Register(nameof(Table),
typeof(IEnumerable<Record>), typeof(IndexedTextBox), new PropertyMetadata(null, TableChangedCallback));
public static readonly DependencyProperty IndexProperty = DependencyProperty.Register(nameof(Index),
typeof(int), typeof(IndexedTextBox), new PropertyMetadata(0, IndexChangedCallback));
private static void TableChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) =>
((IndexedTextBox)d).SetText();
private static void IndexChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) =>
((IndexedTextBox)d).SetText();
private void SetText()
{
if (Table != null)
{
int index = Index;
if (Table.Any(t => t.Index == index))
Text = Table.Where(t => t.Index == index).FirstOrDefault().Value;
else
Text = "N/A";
}
}
public IEnumerable<Record> Table
{
get => (IEnumerable<Record>)GetValue(TableProperty);
set => SetValue(TableProperty, value);
}
public int Index
{
get => (int)GetValue(IndexProperty);
set => SetValue(IndexProperty, value);
}
}
I created a UserControl1 that wraps a DataGrid (this is simplified for test purposes, the real scenario involves a third-party control but the issue is the same). The UserControl1 is used in the MainWindow of the test app like so:
<test:UserControl1 ItemsSource="{Binding People,Mode=OneWay,ElementName=Self}"
SelectedItems="{Binding SelectedPeople, Mode=TwoWay, ElementName=Self}"/>
Everything works as expected except that when a row is selected in the DataGrid, the SelectedPeople property is always set to null.
The row selection flow is roughly: UserControl1.DataGrid -> UserControl1.DataGrid_OnSelectionChanged -> UserControl1.SelectedItems -> MainWindow.SelectedPeople
Debugging shows the IList with the selected item from the DataGrid is being passed to the SetValue call of the SelectedItems dependency property. But when the SelectedPeople setter is subsequently called (as part of the binding process) the value passed to it is always null.
Here's the relevant UserControl1 XAML:
<Grid>
<DataGrid x:Name="dataGrid" SelectionChanged="DataGrid_OnSelectionChanged" />
</Grid>
In the code-behind of UserControl1 are the following definitions for the SelectedItems dependency properties and the DataGrid SelectionChanged handler:
public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register("SelectedItems", typeof(IList), typeof(UserControl1), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedItemsChanged));
public IList SelectedItems
{
get { return (IList)GetValue(SelectedItemsProperty); }
set
{
SetValue(SelectedItemsProperty, value);
}
}
private bool _isUpdatingSelectedItems;
private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctrl = d as UserControl1;
if ((ctrl != null) && !ctrl._isUpdatingSelectedItems)
{
ctrl._isUpdatingSelectedItems = true;
try
{
ctrl.dataGrid.SelectedItems.Clear();
var selectedItems = e.NewValue as IList;
if (selectedItems != null)
{
var validSelectedItems = selectedItems.Cast<object>().Where(item => ctrl.ItemsSource.Contains(item) && !ctrl.dataGrid.SelectedItems.Contains(item)).ToList();
validSelectedItems.ForEach(item => ctrl.dataGrid.SelectedItems.Add(item));
}
}
finally
{
ctrl._isUpdatingSelectedItems = false;
}
}
}
private void DataGrid_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!_isUpdatingSelectedItems && sender is DataGrid)
{
_isUpdatingSelectedItems = true;
try
{
var x = dataGrid.SelectedItems;
SelectedItems = new List<object>(x.Cast<object>());
}
finally
{
_isUpdatingSelectedItems = false;
}
}
}
Here is definition of SomePeople from MainWindow code-behind:
private ObservableCollection<Person> _selectedPeople;
public ObservableCollection<Person> SelectedPeople
{
get { return _selectedPeople; }
set { SetProperty(ref _selectedPeople, value); }
}
public class Person
{
public Person(string first, string last)
{
First = first;
Last = last;
}
public string First { get; set; }
public string Last { get; set; }
}
I faced the same problem, i dont know reason, but i resolved it like this:
1) DP
public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register("SelectedItems", typeof(object), typeof(UserControl1),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedItemsChanged));
public object SelectedItems
{
get { return (object) GetValue(SelectedItemsProperty); }
set { SetValue(SelectedItemsProperty, value); }
}
2) Grid event
private void DataGrid_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var SelectedItemsCasted = SelectedItems as IList<object>;
if (SelectedItemsCasted == null)
return;
foreach (object addedItem in e.AddedItems)
{
SelectedItemsCasted.Add(addedItem);
}
foreach (object removedItem in e.RemovedItems)
{
SelectedItemsCasted.Remove(removedItem);
}
}
3) In UC which contain UserControl1
Property:
public IList<object> SelectedPeople { get; set; }
Constructor:
public MainViewModel()
{
SelectedPeople = new List<object>();
}
I know this is a super old post- but after digging through this, and a few other posts which address this issue, I couldn't find a complete working solution. So with the concept from this post I am doing that.
I've also created a GitHub repo with the complete demo project which contains more comments and explanation of the logic than this post. MultiSelectDemo
I was able to create an AttachedProperty (with some AttachedBehavour logic as well to set up the SelectionChanged handler).
MultipleSelectedItemsBehaviour
public class MultipleSelectedItemsBehaviour
{
public static readonly DependencyProperty MultipleSelectedItemsProperty =
DependencyProperty.RegisterAttached("MultipleSelectedItems", typeof(IList), typeof(MultipleSelectedItemsBehaviour),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, MultipleSelectedItemsChangedCallback));
public static IList GetMultipleSelectedItems(DependencyObject d) => (IList)d.GetValue(MultipleSelectedItemsProperty);
public static void SetMultipleSelectedItems(DependencyObject d, IList value) => d.SetValue(MultipleSelectedItemsProperty, value);
public static void MultipleSelectedItemsChangedCallback(object sender, DependencyPropertyChangedEventArgs e)
{
if (sender is DataGrid dataGrid)
{
if (e.NewValue == null)
{
dataGrid.SelectionChanged -= DataGrid_SelectionChanged;
}
else
{
dataGrid.SelectionChanged += DataGrid_SelectionChanged;
}
}
}
private static void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (sender is DataGrid dataGrid)
{
var selectedItems = GetMultipleSelectedItems(dataGrid);
if (selectedItems == null) return;
foreach (var item in e.AddedItems)
{
try
{
selectedItems.Add(item);
}
catch (ArgumentException)
{
}
}
foreach (var item in e.RemovedItems)
{
selectedItems.Remove(item);
}
}
}
}
To use it, one critical thing within the view model, is that the view model collection must be initialized so that the attached property/behaviour sets up the SelectionChanged handler. In this example I've done that in the VM constructor.
public MainWindowViewModel()
{
MySelectedItems = new ObservableCollection<MyItem>();
}
private ObservableCollection<MyItem> _myItems;
public ObservableCollection<MyItem> MyItems
{
get => _myItems;
set => Set(ref _myItems, value);
}
private ObservableCollection<MyItem> _mySelectedItems;
public ObservableCollection<MyItem> MySelectedItems
{
get => _mySelectedItems;
set
{
// Remove existing handler if there is already an assignment made (aka the property is not null).
if (MySelectedItems != null)
{
MySelectedItems.CollectionChanged -= MySelectedItems_CollectionChanged;
}
Set(ref _mySelectedItems, value);
// Assign the collection changed handler if you need to know when items were added/removed from the collection.
if (MySelectedItems != null)
{
MySelectedItems.CollectionChanged += MySelectedItems_CollectionChanged;
}
}
}
private int _selectionCount;
public int SelectionCount
{
get => _selectionCount;
set => Set(ref _selectionCount, value);
}
private void MySelectedItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// Do whatever you want once the items are added or removed.
SelectionCount = MySelectedItems != null ? MySelectedItems.Count : 0;
}
And finally to use it in the XAML
<DataGrid Grid.Row="0"
ItemsSource="{Binding MyItems}"
local:MultipleSelectedItemsBehaviour.MultipleSelectedItems="{Binding MySelectedItems}" >
</DataGrid>
I have to write an ExtendedStackPanel control which will have two dependency properties like this.
<ExtendedStackPanel IsReadOnly="{Binding Item.IsReadOnly, Mode=OneWay}" >
<TemplateTrue>
... control visible when isreadonly is true
</TemplateTrue>
<TemplateFalse>
... control visible when isreadonly is false
</TemplateFalse>
</ExtendedStackPanel>
I've written this to achieve the goal but it's not working.
public class ExtendedStackPanel : StackPanel
{
public ExtendedStackPanel()
: base()
{
this.Orientation = System.Windows.Controls.Orientation.Vertical;
}
#region IsReadOnly
public bool IsReadOnly
{
get { return (bool)GetValue(IsReadOnlyProperty); }
set { SetValue(IsReadOnlyProperty, value); }
}
public static readonly DependencyProperty IsReadOnlyProperty =
DependencyProperty.Register("IsReadOnly", typeof(bool),
typeof(ExtendedStackPanel), new PropertyMetadata(new PropertyChangedCallback(OnReadOnlyChanged)));
static void OnReadOnlyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var visible = (bool)e.NewValue;
var control = d as ExtendedStackPanel;
if (visible)
{
control.TemplateTrue.Visibility = Visibility.Visible;
control.TemplateFalse.Visibility = Visibility.Collapsed;
}
else
{
control.TemplateTrue.Visibility = Visibility.Collapsed;
control.TemplateFalse.Visibility = Visibility.Visible;
}
}
#endregion
#region TemplateTrue
public Control TemplateTrue
{
get { return (Control)GetValue(TemplateTrueProperty); }
set { SetValue(TemplateTrueProperty, value); }
}
public static readonly DependencyProperty TemplateTrueProperty =
DependencyProperty.Register("TemplateTrue", typeof(Control),
typeof(ExtendedStackPanel), new PropertyMetadata(new PropertyChangedCallback(OnTemplateTrueChanged)));
static void OnTemplateTrueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as ExtendedStackPanel;
control.TemplateTrue.Visibility = control.IsReadOnly ? Visibility.Visible : Visibility.Collapsed;
}
#endregion
#region TemplateFalse
public Control TemplateFalse
{
get { return (Control)GetValue(TemplateFalseProperty); }
set { SetValue(TemplateFalseProperty, value); }
}
public static readonly DependencyProperty TemplateFalseProperty =
DependencyProperty.Register("TemplateFalse", typeof(Control),
typeof(ExtendedStackPanel), new PropertyMetadata(new PropertyChangedCallback(OnTemplateFalseChanged)));
static void OnTemplateFalseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as ExtendedStackPanel;
control.TemplateFalse.Visibility = !control.IsReadOnly ? Visibility.Visible : Visibility.Collapsed;
}
#endregion
}
In my code, I have put a combobox control when IsReadOnly is set to false, and a simple textbox when IsReadOnly is set to true but nothing is displayed when code is run.
Help me please.
Finally, I choose to use a UserControl, in which I put two ContentControl.
In code behind of the UserControl, I write this:
public partial class ConditionalControl : UserControl, INotifyPropertyChanged
{
public ConditionalControl()
{
InitializeComponent();
this.IsReadOnly = false;
}
#region IsReadOnly
public bool IsReadOnly
{
get { return (bool)GetValue(IsReadOnlyProperty); }
set { SetValue(IsReadOnlyProperty, value); }
}
public static readonly DependencyProperty IsReadOnlyProperty =
DependencyProperty.Register("IsReadOnly", typeof(bool),
typeof(ConditionalControl), new PropertyMetadata(new PropertyChangedCallback(OnReadOnlyChanged)));
static void OnReadOnlyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var visible = (bool)e.NewValue;
var control = d as ConditionalControl;
if (visible)
{
control.TemplateTrueContent.Visibility = Visibility.Visible;
control.TemplateFalseContent.Visibility = Visibility.Collapsed;
}
else
{
control.TemplateTrueContent.Visibility = Visibility.Collapsed;
control.TemplateFalseContent.Visibility = Visibility.Visible;
}
}
#endregion
#region TemplateFalse
public object TemplateFalse
{
get { return (object)GetValue(TemplateFalseProperty); }
set { SetValue(TemplateFalseProperty, value); }
}
public static readonly DependencyProperty TemplateFalseProperty =
DependencyProperty.Register("TemplateFalse", typeof(object),
typeof(ConditionalControl), new PropertyMetadata(new PropertyChangedCallback(OnTemplateFalseChanged)));
static void OnTemplateFalseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as ConditionalControl;
control.TemplateFalseContent.Visibility = !control.IsReadOnly ? Visibility.Visible : Visibility.Collapsed;
control.OnPropertyChanged("TemplateFalse");
}
#endregion
#region TemplateTrue
public object TemplateTrue
{
get { return (object)GetValue(TemplateTrueProperty); }
set { SetValue(TemplateTrueProperty, value); }
}
public static readonly DependencyProperty TemplateTrueProperty =
DependencyProperty.Register("TemplateTrue", typeof(object),
typeof(ConditionalControl), new PropertyMetadata(new PropertyChangedCallback(OnTemplateTrueChanged)));
static void OnTemplateTrueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as ConditionalControl;
control.TemplateTrueContent.Visibility = control.IsReadOnly ? Visibility.Visible : Visibility.Collapsed;
control.OnPropertyChanged("TemplateTrue");
}
#endregion
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (propertyName == "TemplateFalse")
{
this.TemplateFalseContent.Content = this.TemplateFalse;
}
if (propertyName == "TemplateTrue")
{
this.TemplateTrueContent.Content = this.TemplateTrue;
}
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Hope this will help someone.
I have created a custom TextEditor control that inherits from AvalonEdit. I have done this to facilitate the use of MVVM and Caliburn Micro using this editor control. The [cut down for display purposes] MvvTextEditor class is
public class MvvmTextEditor : TextEditor, INotifyPropertyChanged
{
public MvvmTextEditor()
{
TextArea.SelectionChanged += TextArea_SelectionChanged;
}
void TextArea_SelectionChanged(object sender, EventArgs e)
{
this.SelectionStart = SelectionStart;
this.SelectionLength = SelectionLength;
}
public static readonly DependencyProperty SelectionLengthProperty =
DependencyProperty.Register("SelectionLength", typeof(int), typeof(MvvmTextEditor),
new PropertyMetadata((obj, args) =>
{
MvvmTextEditor target = (MvvmTextEditor)obj;
target.SelectionLength = (int)args.NewValue;
}));
public new int SelectionLength
{
get { return base.SelectionLength; }
set { SetValue(SelectionLengthProperty, value); }
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged([CallerMemberName] string caller = null)
{
var handler = PropertyChanged;
if (handler != null)
PropertyChanged(this, new PropertyChangedEventArgs(caller));
}
}
Now, in the view that holds this control, I have the following XAML:
<Controls:MvvmTextEditor
Caliburn:Message.Attach="[Event TextChanged] = [Action DocumentChanged()]"
TextLocation="{Binding TextLocation, Mode=TwoWay}"
SyntaxHighlighting="{Binding HighlightingDefinition}"
SelectionLength="{Binding SelectionLength,
Mode=TwoWay,
NotifyOnSourceUpdated=True,
NotifyOnTargetUpdated=True}"
Document="{Binding Document, Mode=TwoWay}"/>
My issue is SelectionLength (and SelectionStart but let us just consider the length for now as the problem is the same). If I selected something with the mouse, the binding from the View to my View Model works great. Now, I have written a find and replace utility and I want to set the SelectionLength (which has get and set available in the TextEditor control) from the code behind. In my View Model I am simply setting SelectionLength = 50, I implement this in the View Model like
private int selectionLength;
public int SelectionLength
{
get { return selectionLength; }
set
{
if (selectionLength == value)
return;
selectionLength = value;
Console.WriteLine(String.Format("Selection Length = {0}", selectionLength));
NotifyOfPropertyChange(() => SelectionLength);
}
}
when I set SelectionLength = 50, the DependencyProperty SelectionLengthProperty does not get updated in the MvvmTextEditor class, it is like the TwoWay binding to my control is failing but using Snoop there is no sign of this. I thought this would just work via the binding, but this does not seem to be the case.
Is there something simple I am missing, or will I have to set up and event handler in the MvvmTextEditor class which listens for changes in my View Model and updated the DP itself [which presents it's own problems]?
Thanks for your time.
This is because the Getter and Setter from a DependencyProperty is only a .NET Wrapper. The Framework will use the GetValue and SetValue itself.
What you can try is to access the PropertyChangedCallback from your DependencyProperty and there set the correct Value.
public int SelectionLength
{
get { return (int)GetValue(SelectionLengthProperty); }
set { SetValue(SelectionLengthProperty, value); }
}
// Using a DependencyProperty as the backing store for SelectionLength. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectionLengthProperty =
DependencyProperty.Register("SelectionLength", typeof(int), typeof(MvvmTextEditor), new PropertyMetadata(0,SelectionLengthPropertyChanged));
private static void SelectionLengthPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var textEditor = obj as MvvmTextEditor;
textEditor.SelectionLength = e.NewValue;
}
Here is another answer if you are still open. Since SelectionLength is already defined as a dependency property on the base class, rather than create a derived class (or add an already existing property to the derived class), I would use an attached property to achieve the same functionality.
The key is to use System.ComponentModel.DependencyPropertyDescriptor to subscribe to the change event of the already existing SelectionLength dependency property and then take your desired action in the event handler.
Sample code below:
public class SomeBehavior
{
public static readonly DependencyProperty IsEnabledProperty
= DependencyProperty.RegisterAttached("IsEnabled",
typeof(bool), typeof(SomeBehavior), new PropertyMetadata(OnIsEnabledChanged));
public static void SetIsEnabled(DependencyObject dpo, bool value)
{
dpo.SetValue(IsEnabledProperty, value);
}
public static bool GetIsEnabled(DependencyObject dpo)
{
return (bool)dpo.GetValue(IsEnabledProperty);
}
private static void OnIsEnabledChanged(DependencyObject dpo, DependencyPropertyChangedEventArgs args)
{
var editor = dpo as TextEditor;
if (editor == null)
return;
var dpDescriptor = System.ComponentModel.DependencyPropertyDescriptor.FromProperty(TextEditor.SelectionLengthProperty,editor.GetType());
dpDescriptor.AddValueChanged(editor, OnSelectionLengthChanged);
}
private static void OnSelectionLengthChanged(object sender, EventArgs e)
{
var editor = (TextEditor)sender;
editor.Select(editor.SelectionStart, editor.SelectionLength);
}
}
Xaml below:
<Controls:TextEditor Behaviors:SomeBehavior.IsEnabled="True">
</Controls:TextEditor>
This is how I did this...
public static readonly DependencyProperty SelectionLengthProperty =
DependencyProperty.Register("SelectionLength", typeof(int), typeof(MvvmTextEditor),
new PropertyMetadata((obj, args) =>
{
MvvmTextEditor target = (MvvmTextEditor)obj;
if (target.SelectionLength != (int)args.NewValue)
{
target.SelectionLength = (int)args.NewValue;
target.Select(target.SelectionStart, (int)args.NewValue);
}
}));
public new int SelectionLength
{
get { return base.SelectionLength; }
//get { return (int)GetValue(SelectionLengthProperty); }
set { SetValue(SelectionLengthProperty, value); }
}
Sorry for any time wasted. I hope this helps someone else...
In my application i'm trying to load the main module trough code. Everything works up to the point of rendering and i have NO clue why it isn't rendering. The content has the right values and everything.. My guess is that something went wibbly wobbly and I seem to be missing it.
Control that holds the view
[ContentPropertyAttribute("ContentView")]
public class ContentControlExtened : ContentControl
{
public static readonly DependencyProperty ContentProperty =
DependencyProperty.Register(
"Type",
typeof(Type),
typeof(ContentControl),
new FrameworkPropertyMetadata(null, ContentTypeChanged));
public static readonly DependencyProperty ContentViewProperty =
DependencyProperty.Register(
"View",
typeof(FrameworkElement),
typeof(ContentControl),
new FrameworkPropertyMetadata(null, ContentViewChanged));
private static void ContentViewChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//throw new NotImplementedException();
}
public ContentControlExtened()
{
this.Loaded += ContentControlLoaded;
}
private void ContentControlLoaded(object sender, RoutedEventArgs e)
{
this.LoadContent();
}
private void LoadContent()
{
UserControl u = null;
if (Type != null)
{
u = (UserControl)ServiceLocator.Current.GetInstance(this.Type);
}
u.Background = new SolidColorBrush(Color.FromRgb(0, 0, 255));
this.View = u;
}
public Type Type
{
get { return (Type)GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}
public FrameworkElement View
{
get { return (FrameworkElement)GetValue(ContentProperty); }
set
{
SetValue(ContentProperty, value);
}
}
}
Method in shell to load the main view of the given moduleInfo
private void OpenMainView(ModuleInfo module)
{
Type moduleType = Type.GetType(module.ModuleType);
var moduleMainViewType = moduleType.Assembly.GetType(moduleType.Namespace + ".Views.MainView");
this.ContentHolder.MainContent.Type = moduleMainViewType;
}
The contructor of the mainview is straight forward. Just standard control InitializeComponent() and Datacontext is being set trough the servicelocator.
public FrameworkElement View
{
get { return (FrameworkElement)GetValue(ContentProperty); }
set
{
SetValue(ContentProperty, value);
}
}
Here you are getting and setting the ContentProperty. It should be ContentViewProperty.