WPF MVVM User Control binding issues - wpf

I have an application that uses MVVM. I have several items on the main window that bind to the ViewModel for that window. When I run it everything works. However, when I add a user control to the main window and try to bind to one of its dependency objects it throws an exception (“Object reference not set to an instance of an object”). The exception window just pops up on the screen and does not link to any particular place in code. And any other information in the exception is not helpful.
I’ve tried my best to trace this down but I’m not having any luck. In the constructor of window I’ve checked and verified that the item that it’s attempting to bind to exists and is an object (int[]). I’ve also manually set the property in the constructor with problems.
Here are some code snippets if anyone can notice anything.
Here is where I use the user control and attempt to bind to the 'view' property
<local:Histogram Grid.Row="2" Grid.ColumnSpan="2"
View="{Binding Path=HistogramData}"
Foreground="{DynamicResource FontColor}"
BucketStroke="{DynamicResource BucketStrokeBrush}"
BucketFill="{DynamicResource BucketFillBrush}"
SelectedBrush="{DynamicResource FamilyEditListViewSelectedBrush}"
DisabledForegroundBrush="{DynamicResource DisabledForegroundBrush}"
AxisBrush="{DynamicResource AxisBrush}"
MaxHeight="130" />
Here is the field in the view model that I am attempting to bind to:
public int[] HistogramData
{
get
{
return histogramData;
}
set
{
if (value != histogramData)
{
histogramData = value;
RaisePropertyChanged("HistogramData");
}
}
}
And in the constructor of the view model I instantiate the object
histogramData = new int[256];
And finally here is the view property in the user control
public static readonly DependencyProperty ViewProperty =
DependencyProperty.Register("View",
typeof(int[]),
typeof(Histogram),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(ViewProperty_Changed)));
public int[] View
{
get { return (int[])GetValue(ViewProperty); }
set { SetValue(ViewProperty, value); }
}
I don't know if this is enough information to solve anything so if more code is req please let me know. I could also zip up the project if someone is so inclined to look at that. Thanks in advance.

You could try initialising the array when you initialise FrameworkPropertyMetaData on the dependency property.
new FrameworkPropertyMetadata(new int [256],
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(ViewProperty_Changed))
I think that the program might be hitting a null reference exception before it manages to bind the dependency property to the viewmodel property.
Ok I've had a look at your example project and think i have a solution.
change the int[] in the viewmodel to a List<int>.
I'm not sure why this works. I hope there is no technical reason that list<int> is not suitable for you.
Here is what I have changed in the solution
in the viewmodel
public List<int> CustomData
{
get
{
return new List<int>(){0,1,2,3};
}
set
{
}
}
In the arraycontrol codebehind
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data",
typeof(List<int>),
typeof(ArrayControl),
new FrameworkPropertyMetadata(new List<int>()));
public List<int> Data
{
get { return (List<int>)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
In arraycontrol.xaml. Just added listbox to show data binding working
<UserControl x:Class="UserControlWithArray.Controls.ArrayControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<Grid>
<TextBlock x:Name="MessageTextBlock" Text="ArrayControl"/>
<ListBox ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=Data}"/>
</Grid>
</UserControl>

Use the debugger to get an exception stack trace. That should help you narrow the problem down.
There are several ways to do this. For example, you should be able to just view the details of the exception. Or you could open a watch window and enter the expression $exception and then hit evaluate.

Related

bind dependency property from custom class to UI

have tried for almost a hole week to find how to bind my dependency property that is in a custom class (Elements) to a simple text box,
Text inside textbox must change every time when i send particular data, this is happening for the first time only,after that, textbox want be updated ??
i have tried every single example but i could not reach my goal, here is my code :
for the class where the depency object created :
public class Elements : DependencyObject
{
public static DependencyProperty TextDataProperty = DependencyProperty.Register
(
"TextData",
typeof(string),
typeof(Elements),
new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.AffectsRender)
);
public string TextData
{
get
{
return (string)GetValue(TextDataProperty);
}
set
{
SetValue(TextDataProperty, value);
}
}
public void UpdateText(string sdata)
{
TextData = sdata;
}
}
i have refere to this class in xaml like so
xmlns:local="clr-namespace:WpfApplication1"
and to use it :
<Window.Resources>
<local:Elements x:Key="myElements" ></local:Elements>
</Window.Resources>
the text box that need to be updated is binded to the custom class like this :
<TextBox
Height="23"
HorizontalAlignment="Left"
Margin="12,61,0,0"
Name="textBox1"
VerticalAlignment="Top"
Width="237"
Text="{Binding TextData, Source={StaticResource myElements}}"
/>
what im doing wrong ?? can someone help please
From your comment: You are creating a new Elements object in
Elements _elements = new Elements();
_elements.UpdateText(textBox2.Text);
This is not the object that is used for the binding in
Text="{Binding TextData, Source={StaticResource myElements}}"
Change your code so that it accesses the object from the Resources:
var elements = (Elements)Resources["myElements"];
elements.UpdateText(textBox2.Text);
Then you should replace the TextBox by a TextBlock, because you only want to display text, but do not want the user to edit it.
You should also take a look at the MVVM design pattern and how it is used in WPF. There are plenty of online resources available.

Design-Time setup of a ViewModel

I'm using Visual Studio 2013's designer to create my User Control in WPF, and I'm using a MVVM approach.
I'm trying to find the best way to have "Design-Time" setup of my viewmodel so that I immediatly see the effect in the designer of changing a value of a property for instance. I've used different designs and techniques to support this, but nothing is exactly what I want. I'm wondering if someone has better ideas...
Situation (simplified):
So I have a "Device" which I want a UserControl to show states and operations. From top to bottom:
I have a IDeviceModel which has a field bool IsConnected {get;} (and proper notification of state changes)
I have a FakeDeviceModel which implements IDeviceModel, and thus enables me to not rely on a real device for design-time and testing
A DeviceViewModel, which contains a IDeviceModel, and encapsulate the model's properties. (yes it has proper INotifyPropertyChanged notifications in it)
My UserControl which will have a DataContext of type DeviceViewModel, and would have a custom-styled CheckBox which is IsChecked={Binding IsConnected, Mode=OneWay
My Goal: I want to preview on design time how does the Model's IsConnected state affect my UserControl (So it could affect other things than just IsChecked)
Framework:
I use the idea of the MVVM Light ViewModelLocator, returning non-static fields (so new instances of ViewModels). At runtime, the real datacontext will be given by the one instanciating this UserControl
d:DataContext="{Binding DeviceViewModelDesignTime, Source={StaticResource ViewModelLocator}}"
public class ViewModelLocator
{
private static MainWindowViewModel _mainWindowViewModel;
public MainWindowViewModel MainWindowViewModelMainInstance
{
get
{
if (_mainWindowViewModel == null)
{
_mainWindowViewModel = new MainWindowViewModel();
}
return _mainWindowViewModel;
}
}
public DeviceViewModel DeviceViewModelDesignTime
{
get
{
//Custom initialization of the dependencies here
//Could be to create a FakeDeviceModel and assign to constructor
var deviceViewModel = new DeviceViewModel();
//Custom setup of the ViewModel possible here
//Could be: deviceViewModel.Model = new FakeDeviceModel();
return deviceViewModel;
}
}
Solutions I tried:
Compile-Time solution
Simply code the setup of the ViewModel in the ViewModelLocator.
var deviceViewModel = new DeviceViewModel(fakeDeviceModel);
var fakeDeviceModel = new FakeDeviceModel();
fakeDeviceModel.IsConnected = true;
deviceViewModel.AddDevice(fakeDeviceModel);
Pros: Simple
Cons: That's longer iterations of always going to change the value in code, recompile, go back to designer view, wait for result
Instance in resources and kept static in ViewModelLocator
So I create an instance in XAML and I try to push it in the current ViewModel used by the designer. Not the cleanest way, but worked for a while in simple situation (yes there's some wierdness with the collection, but was with the idea that I could have multiple devices and a current one)
XAML:
<UserControl x:Class="Views.StepExecuteView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DataContext="{Binding DeviceViewModelDesignTime, Source={StaticResource ViewModelLocator}}">
<UserControl.Resources>
<viewModels:DesignTimeDeviceManager x:Key="DesignTimeDeviceManager">
<viewModels:DesignTimeDeviceManager.DesignTimeDevices>
<device:FakeDeviceModel IsConnected="True"
IsBusy="False"
IsTrayOpen="True"
NumberOfChipSlots="4"
/>
</viewModels:DesignTimeDeviceManager.DesignTimeDevices>
[... CheckBox binding to datacontext and so on...]
And ViewModelLocator.cs:
public class ViewModelLocator
{
private static MainWindowViewModel _mainWindowViewModel;
public MainWindowViewModel MainWindowViewModelMainInstance
{
get
{
if (_mainWindowViewModel == null)
{
_mainWindowViewModel = new MainWindowViewModel();
}
return _mainWindowViewModel;
}
}
public static FakeDeviceModel DeviceModelToAddInDesignTime;
public DeviceViewModel DeviceViewModelDesignTime
{
get
{
var deviceViewModel = new DeviceViewModel();
if (DeviceModelToAddInDesignTime != null)
deviceViewModel.AddDevice(DeviceModelToAddInDesignTime );
return deviceViewModel;
}
}
}
public class DesignTimeDeviceManager
{
private ObservableCollection<FakeDeviceModel> _DesignTimeDevices;
public ObservableCollection<FakeDeviceModel> DesignTimeDevices
{
get { return _DesignTimeDevices; }
set
{
if (_DesignTimeDevices != value)
{
_DesignTimeDevices = value;
ViewModelLocator.DeviceModelToAddInDesignTime = value.FirstOrDefault();
}
}
}
}
Pros:
Worked super great on one project. the instance that I had in XAML, I could modify the booleans and I would get -immediate- feedback on how it affects my UserControl. So in the simple situation, the CheckBox's "Checked" state would change and I could modify my styling in real-time, without needing to recompile
Cons:
It stopped working in another project, and this by itself I couldn't find the reason why. But after recompiling and changing stuff, the designer would give me exceptions looking like "Cannot cast "FakeDeviceModel" to "FakeDeviceModel""!! My guess is that the Designer internally compiles and uses caches for those types (C:\Users\firstname.lastname\AppData\Local\Microsoft\VisualStudio\12.0\Designer\ShadowCache). And that in my solution, depending on the ordering of things, I was creating a "FakeDeviceModel" which was assigned to a static instances, and "later on", the next time the ViewModelLocator would be asked for a ViewModel, it would use that instance. However, if in the meantime he "recompiles" or uses a different cache, then it's not "exactly" the same type. So I had to kill the designer (XDescProc) and recompile for it to work, and then fail again a few minutes after. If someone can correct me on this it would be great.
Multi-Binding for d:DataContext and custom converter
The previous solution's problem was pointing me to the fact that the ViewModel and the FakeDeviceModel were created at different moment in time (giving the type/cast problem) and to solve it, I would need to create them at the same time
XAML:
<UserControl x:Class="MeltingControl.Views.DeviceTabView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d">
<d:UserControl.DataContext>
<MultiBinding Converter="{StaticResource DeviceDataContextConverter}">
<Binding Path="DeviceViewModelDesignTime" Source="{StaticResource ViewModelLocator}" />
<Binding>
<Binding.Source>
<device:FakeDeviceModel IsConnected="False"
IsBusy="False"
IsTrayOpen="False"
SerialNumber="DesignTimeSerie"
/>
</Binding.Source>
</Binding>
</MultiBinding>
</d:UserControl.DataContext>
public class DeviceDataContextConverter: IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values == null || values.Length == 0)
return null;
var vm = (DeviceViewModel)values[0];
if (values.Length >= 2)
{
var device = (IDeviceModel)values[1];
vm.AddDevice(device);
}
return vm;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Pros:
-Works super nice! When the binding for the DataContext asks for the ViewModel, I take advantage of the Converter to modify that ViewModel and inject my device before returning it
Cons:
We lose intelissense (with ReSharper), since he doesn't know what type is returned by the converter
Any other ideas or modifications I could make to solve this issue?
You may create a design time ViewModel that returns IsConnected = true based on your view mode (FakeDeviceViewModel) and then set it as a design-time data context:
d:DataContext="{d:DesignInstance viewModels:FakeDeviceViewModel,
IsDesignTimeCreatable=True}"
Where viewModels: is the xaml namespace to the actual view model.
I've documented exactly how I managed to get the perfect setup to see live Design Time data in Visual Studio.
Look at Hint 9 - Design Time DataContext on this page:
ReSharper WPF error: "Cannot resolve symbol "MyVariable" due to unknown DataContext"
I would like to propose an alternative solution.
You could use that same view model for design time data and normal runtime, and check in your (single) viewmodel whether the designer is active and then load the design time data there.
In your view model you would do something like this:
public class ExampleViewModel : ViewModelBase
{
public ExampleViewModel()
{
if (IsInDesignMode == true)
{
LoadDesignTimeData();
}
}
private void LoadDesignTimeData()
{
// Load design time data here
}
}
The IsInDesignMode property could be placed in your view model base class - if you have one - and looks like this:
DesignerProperties.GetIsInDesignMode(new DependencyObject());
Please take a look at my answer here
This is how I am doing it one of my projects using MVVMLight.
Create interface for every viewmodel for which you need separate design time and run time properties and behavior.
Make separate viewmodels for every view - one for run time and another for design time. Derive both viewmodels from the same interface defined above.
Create a static class that has two static methods - one for registering services for run time in the IOC container and another for registering services for design time in the IOC container. I use the same SimpleIOC.Default container. Register appropriate viewmodels in both the methods bound to their interfaces.
public static class MyServiceLocator()
{
public static void RegisterRunTimeServices()
{
ServiceLocator.SetLocatorProvider(() => SimpleIOC.Default);
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register<IAboutViewModel, AboutViewModel>();
}
public static void RegisterDesignTimeServices()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register<IAboutViewModel, DesignTimeAboutViewModel>();
}
In constructor of ViewModelLocator, check if the app is in DesignMode and accordingly call the static method to register services.
public ViewModelLocator()
{
if (ViewModelBase.IsInDesignModeStatic)
{
MyServiceLocator.RegisterDesignTimeServices();
}
else MyServiceLocator.RegisterRunTimeServices();
}
Now, your Views just have to set datacontext as corresponding viewmodel interface instead of viewmodel object. To do that, instead of exposing viewmodel objects to each view from the ViewModelLocator, expose viewmodel interface.
In ViewModelLocator.cs
public IAboutViewModel About
{
get
{
return ServiceLocator.Current.GetInstance<IAboutViewModel>();
}
}
In AboutView.xaml
DataContext="{Binding Source={StaticResource Locator}, Path=About}"
Wherever needed in code, cast the interface to ViewModelBase type to convert it to ViewModel object and use.
In MainViewModel.cs
public class MainViewModel : ViewModelBase
{
private readonly IAboutViewModel _aboutViewModel;
public MainViewModel()
{
_aboutViewModel = ServiceLocator.Current.GetInstance<IAboutViewModel>();
CurrentViewModel = (ViewModelBase) _aboutViewModel;
}
}
So, basically I use DI to inject appropriate viewmodels to each view depending on whether the code is in run time or design time. The ViewModelLocator simply registers either design time or run time viewmodels in the SimpleIOC container. The benefit of this is that there is no mixing of code in viewmodel files and one can also setup the code for multiple design time data without much interference. If you want designtime data to show while the application runs, then also its possible with one line change in code.
I would create an instance of Fake View Model in a separate xaml e.g. DeviceViewModelDataSample.xaml (see example below)
Set Build Action to DesignData
Reference the file as such
<UserControl x:Class="YourNameSpace.YourControl"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DataContext="{d:DesignData Source=/DataSample/DeviceViewModelDataSample.xaml}">
<!-- Skiped details for brevity -->
</UserControl>
DeviceViewModelDataSample.xaml
<vm:DeviceViewModel xmlns:dm="clr-namespace:YourNameSpace.DataModel"
xmlns:vm="clr-namespace:YourNameSpace.ViewModel">
<vm:DeviceViewModel.DeviceManager> <!-- Assuming this is a collection -->
<dm:DeviceModel DeviceName="Fake Device" IsConnected ="true" /> <!-- This creates an instance at design time -->
</vm:DeviceViewModel.DeviceManager>
</vm:DeviceViewModel>

Silverlight - User Control Binding

I am learning Silverlight. In the process, I'm trying to build a custom user control. My ultimate goal is to be able to write the following statement in XAML:
<my:CustomControl>
<my:CustomControl.MainControl>
<Canvas><TextBlock Text="Hello!" /></Canvas>
</my:CustomControl.MainContent>
</my:CustomControl>
The content of the control will be wrapped in a custom border. Once again, this is just a learning exercise. To append my border, I have create the following UserControl:
<UserControl x:Class="CustomControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<Grid x:Name="LayoutRoot">
<Border>
<!-- CustomControl Content -->
</Border>
</Grid>
</UserControl>
The code-behind for this file looks like the following:
public partial class CustomControl : UserControl
{
public UIElement MainContent
{
get { return (UIElement)GetValue(MainContentProperty); }
set { SetValue(MainContentProperty, value); }
}
public static readonly DependencyProperty MainContentProperty =
DependencyProperty.Register("MainContent", typeof(UIElement), typeof(CustomControl),
new PropertyMetadata(null));
public CustomControl()
{
InitializeComponent();
}
}
The thing I am having a problem with is getting the MainContent to appear in my CustomControl. I am confident that I am setting it properly, but I'm not sure how to display it. I really want it to be a DependencyProperty as well so I can take advantage of data binding and animations.
How do I get the MainContent to appear in the CustomControl? Thank you
First you need to wait until the rest of the control has been parsed so you need to hook the loaded event:-
public CustomControl()
{
InitializeComponent();
Loaded += new RoutedEventHandler(CustomControl_Loaded);
}
Then in the loaded event assign your MainControl property to the Child property of the border. To do that its best if you give your Border an x:Name which for now I'll simple call "border".
void CustomControl_Loaded(object sender, RoutedEventArgs e)
{
border.Child = MainControl;
}
That'll get you going. Of course you may need to deal with the MainControl property being changed dynamically so you need add a bool isLoaded field in your control and set that in the loaded event. When true your MainControl setter should assign the incoming value to the border.Child.
Things can start to get more complicated and in fact I don't recommend this approach to creating a custom control. For a better approach see Creating a New Control by Creating a ControlTemplate

ItemsControl MVVM Binding

I have a form that binds to an ViewModel (MVVM). Inside the form I have an ItemsControl that is bound to an element called projects in my DataContext.
When I do a save using a command pattern I save the item and do a retrieve then I want to rebind the ItemsControl to the Projects collection. This part doesn't seem to be working, all my service calls work as expected but my view is not rebound to the new collection with the added item even though it gets returned from the server.
Any help with this would really be appreciated.
XAML
<ItemsControl Name="ProjectGrid"
Background="Transparent" ItemsSource="{Binding Path=Projects}" Margin="0,0,0,0" VerticalAlignment="Top"
ItemContainerStyle="{StaticResource alternatingWithTriggers}"
AlternationCount="2"
ItemTemplate="{StaticResource ItemTemplate}"/>
ViewModel
public ICommand SaveCommand
{
get
{
if (_cmdSave == null)
{
_cmdSave = new RelayCommand(Save, CanSave);
}
return _cmdSave;
}
}
public void Save()
{
MyService.Save();
PopulateModel();
}
private void PopulateModel()
{
Projects = MyService.GetProjects();
}
public ProjectDto[] Projects
{
get { return _projects; }
set
{
if (_projects == value)
return;
_projects = value;
Notify(PropertyChanged, o => Projects);
}
}
Make sure your ViewModel is implementing INotifyPropertyChanged. Your ui wont know about the change if your view model doesnt inform it when the property changes
use a debug converter to ascertain if your binding is failing. there is an example here of how to do this. This is a technique every wpf developer needs.
im pretty sure its your NotifyPropertyChanged that is failing, the debug converter will tell you for certain
As Aran Mulholland already said, implement INotifyPropertyChanged in your ViewModel.
Also, try to use an ObservableCollection for your collections.
And instead of resetting the collection, try to use
Projects.Clear();
MyService.GetProjects().ToList().ForEach(Projects.Add);
And just as a tip, try to make the GetProjects() method async, so it won't block the UI...

How can I add an "IsDirty" property to a LINQ to SQL entity?

I am binding my entities to an edit form in WPF. Within a DataTemplate, I want to be able to set the background color of the root container within a DataTemplate to show it has been changed and these changes have not yet been submitted to the database.
Here's a very simple sample that demonstrates what I'm talking about (forgive errors):
<Page ...>
<Page.DataContext>
<vm:MyPageViewModel /> <!-- Holds reference to the DataContext -->
</Page.DataContext>
<ItemsControl
ItemsSource = {Binding Items}>
<ItemsControl.Resources>
<DataTemplate
DataType="Lol.Models.Item"> <!-- Item is L2S entity -->
<!-- In real life, I use styles to set the background color -->
<TextBlock Text="{Binding IsDirty, StringFormat='Am I dirty? /{0/}'}"/>
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
</Page>
The example just prints out "Am I dirty? yes" or "Am I dirty? no", but you get the idea.
To do this, I'll need to add a public property to my Item (partial class, simple) that can determine if the entity is dirty or not. This is the tough bit.
public partial class Item
{
public bool IsDirty
{
get
{
throw new NotImplementedException("hurf durf");
}
}
}
Outside of the entity, it's pretty simple (as long as you have the DataContext the entity is attached to). Inside, not so much.
What are my options here?
Edit: I don't think there's one good solution here, so suggestions for workarounds are welcome.
(Okay, similar questions exist, but they are all about how to determine this from outside of the entity itself and use the DataContext the entity is attached to.)
If you are using the dbml generated classes, you should be able to implement a couple of partial methods like this:
public partial class SampleEntity
{
partial void OnCreated()
{
this.IsDirty = true;
}
partial void OnLoaded()
{
this.PropertyChanged += (s, e) => this.IsDirty = true;
this.IsDirty = false;
}
public bool IsDirty { get; private set; }
}

Resources