1

In my App.xaml.cs I have a global view model

public partial class App : Application
{
    public static ViewModel viewModel = new ViewModel();
}

and I've always set data context in the code behind like this

public MainWindow(){
  ...
  DataContext = App.viewModel;
  ...
}

However I want to try doing the same thing but in the XAML. How do I select the class and static property from the XAML? So far I have in my UserControl

<UserControl ...
         xmlns:global="clr-namespace:MyMainNamespace"

(App would be under that namespace like this MyMainNamespace.App)

and then I can select 'App' just fine from global like this

<UserControl.Resources>
    <global:App x:Key="test"></global:App>
</UserControl.Resources>

<UserControl.DataContext>
   ??
</UserControl.DataContext>

And further down in the user control I have a combo box that I want to bind to an observable collection inside the viewModel

<Grid>
    <ComboBox Width="150" Height="25" HorizontalAlignment="Left" VerticalAlignment="Top" ></ComboBox>
</Grid>

Edit: I was trying to model my solution after this answer https://stackoverflow.com/a/23714054/1462656

But I could not find a way to select the viewModel object from App without it giving me syntax errors

erotavlas
  • 4,274
  • 4
  • 45
  • 104

1 Answers1

1

You can bind to your resource using a StaticResource binding for the Source, and grab a property off of it using the binding's Path, like this:

<UserControl ...Existing attributes... DataContext="{Binding Source={StaticResource test},
                                                             Path=viewModel}">

If you really want the DataContext in the "attached" format, you could do it like this:

<UserControl.DataContext>
    <Binding Path="viewmodel" Source="{StaticResource test}" />
</UserControl.DataContext>

...but you will have to make viewModel an actual property, it won't work as a field. Your code may also generate an InvalidOperationException

InvalidOperationException: Cannot create more than one System.Windows.Application instance in the same AppDomain.

if App is your application class generated from App.xaml.cs, as the format you use to declare the resource will create a new instance of it. This will happen even with the "inline" syntax above. It isn't caused by the binding, but by the resource declaration.


My preferred way of doing this, would be to just create a view-model class for the control that implements INotifyPropertyChanged, let's just call it MyControlVm for this example. Then set the DataContext like this:

<UserControl.DataContext>
    <local: MyControlVm />
</UserControl.DataContext>

This would allow you to have multiple instance of your UserControl without them all sharing the same state (as your static property of App would).

Bradley Uffner
  • 16,641
  • 3
  • 39
  • 76
  • For me, test is pointing to the App class, but how do set the dataContext to the viewModel property inside App (not to the entire App class)? – erotavlas Nov 24 '17 at 20:21
  • Sorry about that, I misread your code. I've updated my answer. – Bradley Uffner Nov 24 '17 at 20:23
  • ok,what about in the style I wrote above - inside tag – erotavlas Nov 24 '17 at 20:25
  • I'm not 100% sure if it's possible to do it that way, I've never tried. Is there any special reason you want it in that format? The result should be identical. – Bradley Uffner Nov 24 '17 at 20:26
  • I suppose I was just trying to learn different ways to set the data context in my app. That's ok if its not possible or necessary. – erotavlas Nov 24 '17 at 20:31
  • I figured out the binding, but I think you will run in to another problem. The way you declare the resource `App` will cause it to create a new instance of `App`, which I believe is your application class created from `App.xaml.cs`. This isn't allowed, and you will get the exception "InvalidOperationException: Cannot create more than one System.Windows.Application instance in the same AppDomain." – Bradley Uffner Nov 24 '17 at 20:36
  • Updated answer. – Bradley Uffner Nov 24 '17 at 20:40
  • Your right, the first way works fine, but the second way causes an error, although my error was different type - "The invocation of the constructor on type 'MyMainNamespace.App' that matches the specified binding constraints threw an exception" Regardless, I'll try and implement the third suggestion eventually, everyone I've shown this to suggested the same thing. . – erotavlas Nov 24 '17 at 21:15