GraphSharp library - binding layout - wpf

In our project we are using GraphSharp library. We have encountered some problems when we wanted to remove all edges and vertices from graph.
In every example there is, in xaml there is something like that
<zoom:ZoomControl Grid.Row="1" Zoom="0.2" ZoomBoxOpacity="0.5" Background="#ff656565">
<toProjectGraph:EntityGraphLayout x:Name="graphLayout" Margin="10"
Graph="{Binding Path=GraphViewModel.EntityGraph}"
LayoutAlgorithmType="{Binding Path=GraphViewModel.LayoutAlgorithmType, Mode=OneWay}"
OverlapRemovalAlgorithmType="FSA"
HighlightAlgorithmType="Simple"
/>
</zoom:ZoomControl>
xaml creates instance of our class EntityGraphLayout and uses it to visualize everything.
Is it possible in some way to "bind" this instance of EntityGraphLayout to some property in our view model so we can reference it in our view model code?
Or maybe there is a way that we can create instance of this class and tell xaml to get referebce to object from some path.

Sounds like what you want is to create the object in your viewmodel, expose it as a property, and bind it to the Content property of your zoom control, something like this:
viewmodel:
public class ViewModel {
private EntityGraphLayout _layout = new EntityGraphLayout();
public EntityGraphLayout EntityGraphLayoutProperty
{
get { return _layout; }
set { _layout = value; }
}
}
XAML:
<zoom:ZoomControl Content="{Binding EntityGraphLayoutProperty}" Grid.Row="1" Zoom="0.2" ZoomBoxOpacity="0.5" Background="#ff656565" >
</zoom:ZoomControl>
Note that you will need to make sure the DataContext for the zoom control is set to your viewmodel.
If you want it created in XAML, you could also access the object in your viewmodel by referring to it by the graphLayout name you defined in the XAML. This would require a reference to the view in your viewmodel, which may not be ideal.

Related

What is the best way to add new field into Model collection in ViewModel in MVVM app?

I'm writing WPF application with MVVM structure using MVVM Light.
I have class Foo in the Model:
class Foo: ObservableObject
{
private string _propA = String.Empty;
public string PropA
{
get => _propA ;
set
{
if (_propA == value)
{
return;
}
_propA = value;
RaisePropertyChanged("PropA");
}
}
// same for property PropB, PropC, PropD, etc.
}
And I have some collection of Foo objects in the Model:
class FooCollection: ObservableObject
{
private ObservableCollection<Foo> _items = null;
public IEnumerable<Foo> Items
{
get { ... }
set { ... }
}
public string Name { get; set; }
// ...
// and other methods, properties and fields
}
Now I have a ViewModel where this list is populated via some injected provider:
class MainWindowModel: ViewModelBase
{
private FooCollection _fooList;
public FooList
{
get => _fooList;
set
{
_fooList = value;
RaisePropertyChangedEvent(FooList);
}
}
public MainWindowModel(IFooListProvider provider)
{
FooList = provider.GetFooList();
}
}
And the View, with MainWindowModel as data context:
<TextBlock Text={Binding FooList.Name} />
<ItemsControl ItemsSource="{Binding FooList.Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text={Binding PropA} />
<Button Content={Binding PropB} />
<!-- other controls with bindings -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Everything works fine, I can delete and add new items, edit them and etc. All changes in View reflects automatically in ViewModel and Model via bindings and observable objects, and vice versa.
But now I need to add ToggleButton to data template of ItemsControl, which controls visibility of particular item in other part of window. I need IsChecked value in ViewModel, because control in other part of window is Windows Forms control and I can't bind IsChecked directly without ViewModel.
But I don't want to add new property (Visibility, for example) in model classes (Foo, FooCollection), because it is just an interface thing and it doesn't need to be saved or passed somewhere outside ViewModel.
So my question: what is the best way to add new property to Model collection in ViewModel?
I could create new collection of wrappers in ViewModel (some sort of class Wrapper { Foo item, bool Visibility }) and bind it to ItemsControl. But in this case I have to control adding, removing and editing manually and transfer all changes from List<Wrapper> to FooList.Items, so I don't like this solution. Is there any more simple way to achieve this?
Edition to clarify the question. Now I have:
<ItemsControl ItemsSource="{Binding FooList.Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text={Binding PropA} />
<Button Content={Binding PropB} />
<ToggleButton IsChecked={Binding ????????????} />
<!-- other controls with bindings -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I have no field in class to bind IsChecked and I don't want to add it to class, because it's only interface thing and not data model field. How can I, for example, create another collection of bools and bind it to this ItemControl alongside with FooList.Items?
The best place to add the property is of course in the Foo class.
Creating another collection of some other type, add an object per Foo object in the current collection to this one, and then bind to some property of this new object seems like a really bad solution compared to simply adding a property to your current class.
Foo is not an "interface thing", or at least it shouldn't be. It is view model that is supposed to contain properties that the view binds to. There is nothing wrong with adding an IsChecked property to it. This certainly sounds like the best solution in your case.
I'm not sure if I understand why you would need to add a property in the model.
Can't you just use the command property or add an EventTrigger to your toggle button?
(See Sega and Arseny answer for both examples Executing a command on Checkbox.Checked or Unchecked )
This way, when you check the toggleButton, there is a method in your viewModel which enable or disable the visibility property of your Winform control.
To change the visibility of your control from a command in your viewModel, you could use the messenger functionnality of MVVM LIGHT
MVVM Light Messenger - Sending and Registering Objects
The ViewModel sends a message to you're Windows Forms and this one handles the visibility of your control.

How do I bind wpf with specific datacontext from different classes?

Hi guys I am very new to WPF. I have two datacontexts in two different classes which are being binded by the elements in the View producing datatriggers, and one or the other wouldn't work as they cannot bind both datacontexts together. How do I bind xaml from two different classes using datacontext? Is there any alternative way could make it easier?
Class A
public Window1()
{
InitializeComponent();
Appointments = new Appointments();
DataContext = Appointments;
}
Class B
private void FilterAppointments()
{
this.DataContext = this;
...
Firstly, you should never use DataContext = this; in any UserControl in a serious WPF Application. Secondly, you should look up the MVVM design pattern, which provides the idea of a view model for each view. Your Window or UserControl are the 'Views' and your view models are simply classes that contain all of the data properties that you need to display in your view.
Therefore, you should declare a view model class (that implements the INotifyPropertyChanged interface) and put whatever you wanted to data bind into that. Finally, you should set that object as the DataContext property value. In that way, you'll have access to all the data that you need.
Looking again at your question, it just occurred to me that you may have set the DataContext to this so that you could use properties that you declared in your Window or UserControl. If this is the case, then you should not set the DataContext to this, instead using a RelativeSource Binding to access the properties. That would free up the actual DataContext to be set however you like. Try this Binding within the Window or UserControl:
<TextBlock Text="{Binding PropertyName, RelativeSource={RelativeSource
AncestorType={x:Type YourPrefix:YourWindowOrControl}}}" />

WPF Binding to UserControl Custom DependencyProperty

I have a custom UserControl called SongDescription:
<UserControl x:Class="DPTestAp.SongDescription" ...>
<Grid x:Name="LayoutRoot">
<DockPanel Height="50">
<TextBlock x:Name="title" Text="{Binding name}" Width="100" Height="30"/>
<TextBox x:Name="lyrics"/>
</DockPanel>
</Grid>
</UserControl>
I added DependencyProperty to it:
public partial class SongDescription : UserControl
{
public static readonly DependencyProperty SongProperty = DependencyProperty.Register("Song", typeof(Song), typeof(SongDescription));
public Song Song
{
get
{
return (Song)GetValue(SongProperty);
}
set
{
SetValue(SongProperty, value);
updateLyrics()
}
}
private void updateLyrics()
{
lyrics.Text = Song.lyrics;
}
public SongDescription()
{
InitializeComponent();
}
}
The question is: how to bind something to this SongProperty?
I use SongDescription in my main window like this:
<local:SongDescription x:Name="songDescription" Song="{Binding DataContext}"/>
I cannot make my TextBox lyrics show lyrics. In main window I tried to set DataContext to songDescription, like this:
songDescription.DataContext = new Song() { name="Home", lyrics="Hold on, to me as we go" };
or to window itself like this:
DataContext = new Song() { name="Home", lyrics="Hold on, to me as we go" };
I even tried to make Song a resource and bind it to SongProperty like this:
<Window.Resources>
<local:Song x:Key="res" name="Home" lyrics="Hold on, to me as we go"/>
</Window.Resources>
<Grid>
<local:SongDescription x:Name="songDescription" Song="{StaticResource res}"/>
</Grid>
Nothing helped. TextBlock title binds song name fine. But I can't make updateLyrics() method be called. (In real life this method is more complicated, so I can't use Binding like with name).
Thank you!
Yup, so that's a gotcha with dependency properties. You never ever put validation code inside of the accessor methods (get/set) because dependency properties are stored by WPF in a table that it itself manages. This is why you have to register dependency properties, it essentially creates entries on this table for storing the values associated with each property, and when you use 'GetValue' / 'SetValue' you are updating the entries on this table (which by the way relates to how WPF is able to manage data bindings in general).
The upshot of this though is that WPF can (and will) completely bypass your property accessors because it has direct access to the real data. Why should it use your accessors if it can just go to the data directly. Instead you need to implement a 'PropertyChanged' callback function or some WPF sanctioned method of doing validation, but never ever do it in your accessors.
See:
http://msdn.microsoft.com/en-us/library/ms752914.aspx
In addition to sircodesalot's answer, you are not bound on your lyrics textbox. Also, since the song your bound to is a class, you will need to specify the paths fully for the properties you want to show in the boxes such as "Path=Song.Lyrics".
Another thing to consider is that with dependency properties; your mode will be oneway by default so making the text field editable would be moot really unless you change it.
Third, if you're using MVVM you only need your main window context to be set to the view model and have a matching Song property to bind against.

How do you pass a ViewModel to the constructor of a UserControl that is shown in a ContentPresenter?

I have several UserControls that should display the same data. Each UserControl has a different layout of the data that is to be presented. The ContentPresenter can bind to any one of the UserControls by using a DataTemplate in my Resources and by binding the Content to a StyleViewModel. Each UserControl is associated with a ViewModel as defined in the DataType of the DataTemplate. The ViewModels associated with any given UserControl all inherit from the StyleViewModel. The UserControls should get their data from a SettingsViewModel. The UserControls appear in the main Window.
The problem is that I can't figure out how to make the data from the SettingsViewModel accessible to the UserControls.
Is it possible to pass a reference to a SettingsViewModel to the constructor of one of these UserControls that are displayed using a ContentPresenter?
Is there another way to easily switch between different views of the data (i.e. my UserControls) without using a ContentPresenter? If so, how would I make the data accessible to the UserControls?
The following is code from my SingleLineViewModel.cs:
public class SingleLineViewModel : StyleViewModel
{
public SingleLineViewModel() { }
}
The other ViewModels are similar. They are essentially empty classes that inherit from StyleViewModel, so that I can bind to a Style property which is of type StyleViewModel in my SettingsViewModel. The StyleViewModel is also an essentially empty class that inherits from ViewModelBase.
The following is code from my Resources.xaml:
<ResourceDictionary <!--other code here-->
xmlns:vm="clr-namespace:MyProject.ViewModel"
<!--other code here-->
<DataTemplate DataType="{x:Type vm:SingleLineViewModel}">
<vw:ucSingleLine/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:SeparateLinesViewModel}">
<vw:ucSeparateLines/>
</DataTemplate>
<!--other code here-->
</ResourceDictionary>
The following is code from SettingsViewModel.cs:
public class SettingsViewModel : ViewModelBase
{
// other code here
private StyleViewModel _style;
public StyleViewModel Style
{
get { return _style; }
set
{
if (value != _style && value != null)
{
_style = value;
OnPropertyChanged("Style");
}
}
}
// other code here
public SettingsViewModel()
{
_style = new SingleLineViewModel();
}
// other code here
}
The following is code from my MainView.xaml:
<ContentPresenter Name="MainContent" Content="{Binding SettingsVM.Style}"/>
You might find that you are trying to do much at once. Consider how you might test this scenario? Or how would you walk the data in a Debugger to check its state? Good practice recommends that your data is separate from your UI elements. An MVVM pattern such as you are trying to use normally provides the view models to help transition the data from it's simple data into forms that the UI can use.
With that in mind, I would recommend that you try do develop a ViewModel tier that presents all the data without the UI holding it together, i.e. instead of trying to inject the additional SettingsViewModel into your controls you should make your viewmodels hold everything they need.
It looks like you are off to a good start, your SettingsViewModel lets you get hold of a Style, but your style doesn't seem to have any data. So why not pass it in the constructor.
public SettingsViewModel()
{
_style = new SingleLineViewModel(WhatINeedForStyle);
}

How can I bind from a user control to an external object in XAML?

I have an image inside a user control that I want to bind it's visibility to a property I have set up in a class object. The dependency properties are set up and working correctly, but I don't know how to set the binding properly on the image.
The user control and class object are in the same namespace. I thought I would need to set the ElementName to the window or the RelativeSource to the class object, but I'm not getting it to work out.
Here's what a dependency property looks like (defined in MigrateUserWizardObject.cs, this inherits from DependencyObject, this resides in the UserAccountMigrator namespace):
public static readonly DependencyProperty DatabaseStepCompletedVisibilityProperty = DependencyProperty.Register("DatabaseStepCompletedVisibility", typeof(Visibility), typeof(MigrateUserWizardObject));
public Visibility DatabaseStepCompletedVisibility
{
get
{
return (Visibility)GetValue(DatabaseStepCompletedVisibilityProperty);
}
set
{
SetValue(DatabaseStepCompletedVisibilityProperty, value);
}
}
Here's an image that I want bound to this dependency property (defined in ProgressUserControl.xaml, this inherits from UserControl, this resides in the UserAccountMigrator namespace as well):
<Image x:Name="DatabaseCompleted" Source="{StaticResource GreenCheckMarkSource}" Visibility="{Binding Path=DatabaseStepCompletedVisibility, UpdateSourceTrigger=PropertyChanged}" Height="20" HorizontalAlignment="Right"></Image>
This is due to the fact that the DataContext of the image is the user control. How can I make this work?
I think you should look into using the Model-View-ViewModel pattern. Instead of setting the DataContext to the UserControl, set it to an instance of another class (ProgressViewModel, for example). This view model would have all the properties you want to bind to (including your DatabaseStepCompletedVisibility property) and makes it much easier. Right now you are wanting to bind some things to the UserControl, some things to another object somewhere else, etc.. and, as you have found, makes it difficult. Here is more information:
http://jmorrill.hjtcentral.com/Home/tabid/428/EntryId/432/MVVM-for-Tarded-Folks-Like-Me-or-MVVM-and-What-it-Means-to-Me.aspx
Without going that approach, you have to have an instance MigrateUserWizardObject to bind to. You can put that instance in your UserControl (if you insist on using it as the DataContext), then you can bind the the property of the MigrateUserWizardObject property of the UserControl. Also, your MigrateUserWizardObject doesn't have to be a dependency object or dependency property to bind to. A better pattern would be to make it a plain c# class that implements the INotifyPropertyChanged interface.

Resources