Quick way to link Objects from screen to View Model - c#

Out of curiosity, is there a way to do this quicker without defining two string or objects?
Xaml
<TextBox Margin="5" Width="100" Text={Binding Path=dataString}></TextBox>
View Model
string _dataString;
public string dataString
{
get
{
return _dataString;
}
set
{
_dataString = value;
base.OnPropertyChanged();
}
}

You can define helpers to shorten the syntax somewhat. For example, if you use the MVVM Light Toolkit, and inherit your ViewModel from ViewModelBase, the toolkit provides a helper that enables use of the following syntax:
private string _dataString = null;
public string DataString
{
get { return _dataString; }
set { Set(ref _dataString, value); }
}
You still have to provide a backing field, but the helper takes care of notifying the exact property that changed, and only raises the event if the new value is in fact different from the current one.
You can also speed up the process of adding the properties by creating a custom code snippet and importing it into Visual Studio via the Code Snippets Manager.

Related

Make updating a property in one class trigger the setter for a property of that type in another class

I am using MVVM with Galasoft MVVMLight libraries.
I have two models; each has a boolean property and different properties of the same type.
public class Model1 : ObservableObject
{
public EnumPair<YesNoInherit> Model1Property
{
get { return _model1Property; }
set
{
_model1Property = value;
Updated = true
RaisePropertyChanged("Model1Property");
}
}
public bool Updated
{
get { return _updated; }
set
{
_updated = value;
RaisePropertyChanged("Updated");
}
}
}
public class Model2 : ObservableObject
{
public EnumPair<YesNoInherit> Model2Property
{
get { return _model2Property; }
set
{
_model2Property = value;
Updated = true
RaisePropertyChanged("Model2Property");
}
}
public bool Updated
{
get { return _updated; }
set
{
_updated = value;
RaisePropertyChanged("Updated");
}
}
}
The type YesNoInherit is an enum having values No, Yes, and Inherit.
Here is the EnumPair class.
public class EnumPair<T> : ObservableObject where T : struct, IConvertible
{
public T EnumValue
{
get { return _enumValue; }
set
{
if (Type.Equals(value, _enumValue) == false)
{
_enumValue = value;
RaisePropertyChanged();
}
}
}
public string SourceName
{
get { return _sourceName; }
set
{
_sourceName = value;
RaisePropertyChanged();
}
}
}
In my view, I am trying to use a ComboBox to let the user select one of the three enum values, and, in some cases, display custom text. The resource "enumComboBoxTemplate" allows the ComboBox drop-down to show enum descriptions. The converter "inheritanceEnum2Desc" is where the custom text would be applied. "object1" is an instance of "Model1".
<ComboBox ItemTemplate=ItemTemplate="{StaticResource enumComboBoxTemplate}"
EnumSource="enums:YesNoInherit">
<ComboBox.Text>
<MultiBinding Converter="{StaticResource inheritanceEnum2Desc}">
<Binding Path="object1.EnumValue"/>
<Binding Path="object1.SourceName"/>
</MultiBinding>
</ComboBox.Text>
</ComboBox>
"Model2" would be used in future programming employing similar functionality, but with different data.
When I change the selection in the ComboBox, I want to change the value of "Updated" (from false to true) so I can enable a button in the view. This appears to require that the EnumPair class somehow make the program execute the setter for Model1Property. Since the two model classes have properties of type EnumPair, I don't believe I can add any code in EnumPair specific to either model class.
How can I accomplish this? I would greatly appreciate any assistance.
Basically, you have two options: either use some kind of message-bus to update the other model (Prism has EventAggregator, not sure about MVVMLight) or make both model instances forward their properties to a common data source that notifies all of its users when a property changes.
If you want to be able to easily change from one class to another in the future without rewriting all of your code, you need to create an Interface that defines all of the things that the two models have in common, and both model classes need to implement the interface. You could call the interface IModel1
So, instead of having a "Model1" in your viewmodel, you would have an "IModel1" in your viewmodel instead. You could pass in the same object you are passing in now, which is of type Model1, because it implements the IModel1 interface. When you are ready to switch, pass in a Model2 instead, and it will work without having to rewrite anything in your view or viewmodel. Your setters can be completely different - as long as both models have all of the methods and properties that are required by the interface, you will be OK.
Alternately, if Model2 is exactly like Model1 except that it has "extra stuff," you can make Model2 a derived class which derives from Model1.
Google searching either of those terms should point you toward a good tutorial.

Can a markup extension be aliased?

The markup extension that brought me to ask this is Catel's LanguageBinding.
I was until now using Infralution's localization assembly, which works more or less the same way.
Catel:
<TextBlock Text="{LanguageBinding MyText}"/>
Infralution:
<TextBlock Text="{Resx MyText}"/>
But as you can see, the markup extension is way shorter to write, thus less prone to typos.
So I wanted to know if there was any way to be able to use LanguageBinding with another markup extension word, like:
Ideal:
<TextBlock Text="{LB MyText}"/>
I'm well aware of readability issues and such, it's an example.
That's not possible to do directly in XAML but you can derive a class from LanguageBinding and use it. Here's an example for shortening the StaticResource Markup Extension.
class SR : StaticResourceExtension
{
public SR() {}
public SR(object resourceKey)
:base(resourceKey)
{ }
}
Now you need can use something like {local:SR} as an "alias".
You can inherit MarkupExtension to create your own custom Binding tag
[MarkupExtensionReturnType(typeof(object))]
public class LBBinding : MarkupExtension
{
private Binding _binding = new Binding();
public Binding Binding
{
get { return _binding; }
set { _binding = value; }
}
public PropertyPath Path
{
get { return _binding.Path; }
set { _binding.Path = value; }
}
<TextBox Text="{customBinding:LBBinding Path=DummyString}"></TextBox>
You should also override ProvideValue method from MarkupExtension. This method will be trigger whenever WPF perform the actual binding. Use the IServiceProvider to get back your DependencyObject (Control) and the DependencyProperty (Your binding property). Then you can do all the magic you want with those 2 information.
public override object ProvideValue(IServiceProvider provider)
{
var service = (IProvideValueTarget)provider.GetService(typeof(IProvideValueTarget));

Binding sub properties MvvmCross

Does mvvmcross natively support binding to nested properties?
For example I have a view model as follows:
class MainViewModel : MvxViewModel
{
public SubViewModelBase SubViewModel
{
get { return _subViewModel; }
set { _subViewModel = value; RaisePropertyChanged(() => SubViewModel); }
}
}
The sub view model may change, but the MainView will bind to the same properties for ALL SubViewModelBase classes... an example SubViewModelBase class as follows:
class SubViewModelBase : MvxViewModel
{
public bool ShowIndeterminantProgress
{
get { return _showIndeterminantProgress; }
set { _showIndeterminantProgress = value; RaisePropertyChanged(() => ShowIndeterminantProgress);}
}
// ... More common properties ...
}
So the MainView would ideally bind like this
this.CreateBinding(_progressBar)
.For(view=> view.Visibility)
.To<MainViewModel>(vm => vm.SubViewModel.ShowIndeterminantProgress)
.WithConversion("Visibility")
.Apply();
Should this work? It doesn't appear to be working, but there are no binding errors in the output?
Does mvvmcross natively support binding to nested properties?
Yes
Should this work?
Yes
For example, this line in ApiExamples for Xamarin.iOS is working:
set.Bind(errorLabel2).To(vm => vm.Errors.Count);
https://github.com/MvvmCross/MvvmCross-Tutorials/blob/master/ApiExamples/ApiExamples.Touch/Views/FirstView.cs#L361
The set of supported functionality is described in https://github.com/MvvmCross/MvvmCross/wiki/Databinding#fluent - but admittedly this fluent binding is more established/used in Xamarin.iOS than it is in Wpf.
To try to debug why your current binding might not be working try adding a simple property to your view which provides debug output
private Visibility _mockVisibility;
public Visibility MockVisibility
{
get
{
return _mockVisibility;
}
set
{
Debug.WriteLine("MockVisibility called with " + value);
_mockVisibility = value;
}
}
and binding this as:
this.CreateBinding(this)
.For(view=> view.MockVisibility)
.To<MainViewModel>(vm => vm.SubViewModel.ShowIndeterminantProgress)
.WithConversion("Visibility")
.Apply();
This should give you debug/trace output and should give you somewhere to put a breakpoint to understand the call stack a little too (although expect this to contain lots of reflection which can be hard to read through).
Beyond this:
you could also try binding a label's text to see what that displays.
you can also try setting the binding trace level to Diagnostic (using the static field MvxBindingTrace.TraceBindingLevel https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.Binding/MvxBindingTrace.cs#L14)
try isolating the problem piece by piece (isolating the converter, isolating the nested property, etc, etc) - I guess this is what you are already doing in asking this question.

WPF Data Binding TooWay XAML to C# and C# to XAML

I have XAML code:
<TextBox Name="textBoxMask1"/>
<TextBox Name="textBoxMask2"/>
<TextBox Name="textBoxMask3"/>
...
<TextBox Name="textBoxMask9"/>
and class in C#:
private static string mask1;
public static string Mask1
{
get { return mask1; }
set { mask1 = value; }
}
private static string mask2;
public static string Mask2
{
get { return mask2; }
set { mask2 = value; }
}
private static string mask3;
public static string Mask3
{
get { return mask3; }
set { mask3 = value; }
}
....
private static string mask9;
public static string Mask9
{
get { return mask9; }
set { mask9 = value; }
}
And I want to bind these TextBoxes with Properties -> textBoxMask1 with Mask1 etc.
Earlier I did this by TextChanged, but I want to make Binding. TooWay Binding, because I want to predefine Mask1, Mask2, Mask3, ..., Mask9 in another C# class, and maybe later change these values - also in some C# code - and I want my changes, to be visible in layout (XAML) and in C# code - so ex. changing Property Mask1 from C# will change Text in TextBox textBoxMask1, and changing Text in textBoxMask1 will change Property Mask1.
I don't understand, how to make connection (binding) between objects XAML and C#.
For a normal Binding you don't need your properties to be static, just public. Here an example:
C# code (for one property)
private string mask1;
public string Mask1
{
get { return mask1; }
set
{
mask2 = value;
RaisePropertyChanged("Mask1");
}
}
It's really important for the binding that the class containing the properties implements the INotifyPropertyChanged interface, and that you raise the corresponding event in the setter of each property. Another option is to make all properties DependecyProperty, but it is usually overkill.
As for the XAML:
<TextBox Name="textBoxMask1" Text="{Binding Mask1, Mode=TwoWay}"/>
(TwoWay Binding is the default for the Text property, but it does not hurt to put it explicitly).
Just make sure that the DataContext of the object containing your TexBoxes (usually an UserControl) is set to a valid instance of your C# class.
By the way, this is a very basic question, that's why you got a negative vote and no answers before mine. What is expected is that you ask a question that poses a real problem for you, with a very specific answer, not something like "teach me how to do this".
If this answers your question don't forget to mark it as answer (the "tick" mark on the top left). A vote up would be also appreciated.
Hope it helps, regards.

Is there attached property in C# itself?

In C# itself, is there something like "attached property" used in WPF?
The short answer is no. The slightly longer answer is that this is a bit of an unfortunate story. We designed "extension properties" for C# 4 and got as far as implementing (but not testing) them when we realized, oh, wait, the thing we designed is not really compatible with WPF-style properties. Rather than redesign and reimplement the feature we ended up cutting it.
The even longer version is here:
http://blogs.msdn.com/b/ericlippert/archive/2009/10/05/why-no-extension-properties.aspx
AttachedProperties are part of the .NET Framework, not part of the C# language specification, and specifically part of the System.Activities.Presentation.Model namespace, which is WPF specific.
In WPF, an attached property allows you to do something like:
<TextBlock Grid.Row="2" Text="I know nothing about grids!" />
This would be like having a class in C# defined as:
public class TextBlock
{
public string Text { get; set; }
}
And being able to do this:
var tb = new TextBlock();
tb.Grid.Row = 2; // this line would not compile
In order to make this work, you'd need to pass a Grid object into your TextBlock class:
public class TextBlock
{
public string Text { get; set; }
public Grid Grid { get; set; }
public TextBlock(Grid grid)
{
Grid = grid;
}
}
But I don't think there's anything directly equivalent to the way attached properties work in WPF. You'd need to build it by hand.
What are you trying to accomplish?
You can use the ConditionalWeakTable<TKey, TValue> class to attach arbitrary state to an instance. You can combine it with extension methods to create a form of extension properties, but unfortunately without using the nice property syntax in C#.
I think you're thinking of getters and setters.
They are created like this:
public class Person
{
//default constructor
public Person()
{
}
private string _Name;
public string Name
{
//set the person name
set { this._Name = value; }
//get the person name
get { return this._Name; }
}
}
More on how they work here:
http://msdn.microsoft.com/en-us/library/aa287786(v=vs.71).aspx

Categories