How to bind C# generated button to XAML MVVM - c#

So far I have read a lot about binding and I have looked up my question. Unfortunately the questions I stumbled upon, were questions regarding the CONTENT of a button.
My question rather is:
How can I bind a C# generated button (new Button (//CONTENT)) to my XAML, rather then just binding content to my already generated button?
in my MVVM code I have property which holds a button as value called RequestedButton, but I have no idea as to what kind of tag I should use in my XAML to bind this property to.
I do know how to bind this if it were to be a ObservableCollection, but no idea on how to bind it if it's a single attribute.
So my question (to the point) is: What kind of element should I use in my XAML, to use the binding on for the property RequestedButton, to use {Binding RequestedButton} on?
In my class I have a property named RequestedButton, which holds a Button as a value. Like this:
Class Foo
{
public Button RequestedButton {get; set;}
public Foo()
{
RequestedButton = new Button()//GENERATE BUTTON WITH PROPERTIES IN IT
}
}
What tag should I now use, to correctly display (use Binding) the button ABOVE in my XAML?

View Model
private Button requestedButton = new Button();
public Button RequestedButton
{
get
{
return requestedButton;
}
set
{
requestedButton = value;
NotifyPropertyChanged(nameof(RequestedButton));
}
}
...
Xaml
<ContentView Content="{Binding RequestedButton}"/>

Related

WPF: navigating between user controls resets viewmodel

I have an application where I am using usercontrols as "pages" of the application. I have a currentpage binding in ApplicationViewModel on my MainWindow, and I navigate between pages by changing the binding of currentpage with commands attached to a side menu control. I am using the MVVM pattern and all of my ViewModels derive from a BaseViewModel class.
The navigation works, but when I input text into a text box, then navigate away and then back, the user-input text is reset to it's default binding.
I've already tried updating the source trigger and setting the mode to TwoWay. My "page" has a viewmodel which it is bound to, and otherwise works.
On my page, in the parent grid all controls are in:
DataContext="{x:Static core:MyPageViewModel.Instance}">
And the control:
<TextBox Text="{Binding TextBoxTest, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
And in my viewmodel:
public static MyPageViewModel Instance => new MyPageViewModel();
public string TextBoxTest { get; set; } = "Change Me!";
I would like the value I enter to remain when I navigate away, and then return, to the page. I assume it's because when I navigate away from my usercontrol I'm unloading it, and when I navigate back I'm getting a new instance of the viewmodel. I just don't know how to keep a single one that remains in memory.
You should post more code, it's not clear from the pieces.
I can try to guess anyway the problem is here:
public static MyPageViewModel Instance => new MyPageViewModel();
This generates a new ViewModel every time it is accessed by your view, because it is the equivalent of writing:
public static MyPageViewModel Instance { get { return new MyPageViewModel(); } }
instead, you should write something like
public static MyPageViewModel Instance { get; } = new MyPageViewModel();
This way, the first time it is accessed, it returns the default value (new MyPageViewModel()), and now that static variable will always point to the same view model, instead of creating a new one.
Guido C. was exactly correct. I changed my viewmodel instance from the way I had it in my question to this:
public static MyPageViewModel Instance { get; } = new MyPageViewModel();
And it worked.

What is the proper way to create dependency properties in user controls that allow two way bindings

I say proper because all the examples I have seen all seem to contradict each other and or fall short in some respects. I need to be able to bind a class object to my DP from XAML or set it programmatically in cb:
<local:MyControl MyDP="{Binding MyObject}"/>
or
MyControl mycontrol = new MyControl(){MyDP = MyObject};
and then within the control, two way bind elements to properties of the binding object:
<TextBox text="{Binding MyDP.text, ElementName=MyControl}"/>
I would think this is pretty standard stuff, but the lack of cohesion I have seen in people trying to write examples has led me to believe otherwise.
This is how I do it:
Assume a parent control that contains a status bar (User Control) it's markup looks like this:
<ContentControl x:Name="XFoot" Grid.Row="1" Grid.ColumnSpan="3" >
<UserControls:UCStatusBar />
</ContentControl>
Now in the UserControl named status bar it's dependency property looks like this:
public StatusUpdate CurrentStatus
{
get { return (StatusUpdate)GetValue(CurrentStatusProperty); }
set { SetValue(CurrentStatusProperty, value); }
}
// Using a DependencyProperty as the backing store for CurrentStatus. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CurrentStatusProperty =
DependencyProperty.Register("CurrentStatus", typeof(StatusUpdate), typeof(UCStatusBar),
new PropertyMetadata(
new StatusUpdate() { ErrorMessage="", IsIndeterminate=false, Status="Ready"}
)
);
Status Update looks like this, it's just a container for three properties shown in the status bar.
public class StatusUpdate
{
public StatusUpdate()
{
Status = "";
ErrorMessage = "";
IsIndeterminate = true;
}
public string Status { get; set; }
public string ErrorMessage { get; set; }
public bool IsIndeterminate { get; set; }
}
}
Anyone can update the status bar by accessing the CurrentStatus property of the statusbar. NOTE to make a two way binding, that's done in XAML... within the binding directive, just press space bar and the property window will show binding modes. Pick two way.
PS: In Visual Studio, when you first create the DP just type in propdp and press the tab button, the entire DP structure is inserted for you automatically. As a result DPs are easy to implement.
How do DPs work two-way?
If you are using XAML binding you simply tell it via the MODE property that it's two way. This means that the GUI changes will update the properties when user changes the values.
<TextBox Text="{Binding Path=ThePropertyName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
Notice the Mode value and the UpdateSourceTrigger says, don't want for focus to change, update it right away.
Wait a minute, nothing is happening when I bind and make changes!
Three things are required for a binding to work 1) DataContext must be set either in code behind or as a static resource in the XAML 2) The pathname to the property name must exactly the CLR property name and 3) There must be content in the property.
Can I fire an Event from somewhere else to update the property?
Sure... the first step is to set up the static eventhandler in the UserControl like this:
public static EventHandler<string> NewData;
Then in the CTOR wire it up like this:
NewData+=OnNewData;
Then the event handler looks like this:
private void OnNewData(object sender, string data){
//setting this string property notifies WPF to update the GUI
ThePropertyName = data;
}
The other code does this...
MyUserControl.OnNewData(this, "Now is the time for all good men to...");

Bind object properties to a datagrid in WPF

I have the following class:
public class Sp3dItem
{
public Sp3dItem()
{
Items= new ObservableCollection<Sp3dItem>();
}
public string OID
{
get;
set;
}
public string Name
{
get;
set;
}
public string Type
{
get;
set;
}
public ObservableCollection<Sp3dItem> Items
{
get;
set;
}
}
I need to show the properties of an instance of this object to a Datagrid (or any other type of grid). Like the Properties Window in Visual Studio. But there are certain properties that I don't care, like 'Items', I only need to show properties of string Type, and only the ones with non empty values (this last one would be a plus, not a real need).
The question is, can I do something like this with binding or do I have to assembly the data on the grid manually?
Sounds like you want a property grid to view the properties of a single object instance, where each property/value pair is a 'row', yes? If that's the case, look into some of the third-party Property Grid controls. The WPF Extended Toolkit has a free one.
Typically, these grids can automatically discover the properties of the target object, and you can choose to hide certain properties by adorning them with [Browsable(false)].
Yes... it's possible and easy once you figure out how the built-in binding wizard works.
This example is for a
<Label...
Create a static instance to your view model in the View. By doing this the designer will show the properties of the Viewmodel in the
properties page once you start "wiring up the bindings"...
//in code behind
public static string Error
{
get { return _Error; }
set { _Error = value; }
}
Now click on the XMAL component in designer just once.
<Label Grid.Row="2" <=Click here one time
In the properties page, click the icon (small square on far right side of property) to start the binding process
Select "Create Data Binding"
Select 'FindAncestor' then the MainWindow of interest, and finally the static property.
Click ok and the bindings are set in XAML Automatically.
<Label Grid.Row="2"
Content="{
Binding Error,
RelativeSource={
RelativeSource FindAncestor,
AncestorType={x:Type local:MainWindow}}}"/>
The verbosity above just says:
Look in MainWindow's static properties for Error.
Make this Label's content that value.
If you want you can also edit the template for the Datagrid, but that's not relevant to your question.

WPF binding not being set to UserControl DependencyProperty

I've got a ListView which is bound to a list of objects. When I select an item in the ListView, I catch a SelectionChanged event and then pass the selected object off to a details view.
protected void list_selectionChanged(object sender, SelectionChangedEventArgs e) {
var myObject = theList.SelectedItem as MyObjectType;
detailsView.DataContext = myObject;
}
detailsView is a UserControl in the same WPF as the ListView. It contains some XAML like so:
<Label Content="{Binding Path=deviceId}"></Label>
<l:MyUc deviceId="{Binding Path=deviceId}" />
Inside MyUC, I've got a DependencyProperty defined:
public static readonly DependencyProperty deviceIdProperty = DependencyProperty.Register("deviceId", typeof(Guid), typeof(MyUC), new FrameworkPropertyMetadata(null));
public Guid deviceId {
get { return (Guid)GetValue(deviceIdProperty); }
set { SetValue(deviceIdProperty, value); }
}
The Label shows the deviceId, but the property inside MyUC never gets set.
Can anyone spot my mistake?
When you use a Dependency Property in XAML, the set method never gets called. If you want to "see" this set, you need to add a property changed callback, as the binding mechanism directly sets the dependency property without your setter.
For details on how to implement this, see the PropertyChanged callbacks section of MSDN.
First, it would be helpful if you could add the actual XAML code where you define the ListView and it's properties.
Second, you should look at the output console (in Visual Studio debug session of course) and see whether there are binding errors regarding the bindings you defined.
It is very probable that the bindings provide values that does not fit the deviceId dependency property type and thus it never changes.

Initialize control in control

This is my custom control class:
// Extended ComboBox where ill change some property.
public class ExtComboBox : ComboBox
{
...
}
// ExtButton is a control that i am going to drop on Form from ToolBox.
public partial class ExtButton : Button
{
public ExtComboBox ComboBoxInsideButton { get; set; }
public ExtButton()
{
InitializeComponent();
ComboBoxInsideButton = new ExtComboBox();
ComboBoxInsideButton.Text = "hi!";
Controls.Add(ComboBoxInsideButton);
}
}
Basically when i add this control to form there will be ComboBox on top off Button.
Don't ask my why i need this :D
Now if i need to change ComboBox text i simply use:
extButton1.ComboBoxInsideButton.Text = "aaa";
All work fine.. but :) when i am trying to change some ComboBox properties in Design mode (Window Properties -> Expand ComboBoxInsideButton -> Change Text to "bbb")
after rebuilding or running project ComboBox properties will be reseted (ExtButton.Designer.cs)
Question 1: How to initialize subcontrol with some default properties value, so when ill drop control on Form all setting will be added?
and
Question 2: How to change properties of subcontrol on design time.
EDIT:
Answer here: Designer does not generate code for a property of a subcontrol. Why?
Adding [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] solves the problem.
I wrote a mini-tut on how to create custom UserControls and accessing their members here. Pretty much, it looks like you are going to want add properties to your ExtComboBox that expose the ComboBox properties you'd like to change. Then, in ExtButton, you will be able to use the . to change these values at runtime.
Also, instead of doing:
public ExtComboBox ComboBoxInsideButton { get; set; }
...
ComboBoxInsideButton = new ExtComboBox();
do
public ExtComboBox comboBoxInsideButton = null;
...
comboBoxInsideButton = new ExtComboBox();
Be sure to understand the difference between private and public also. I'm not sure if you want your ExtComboBox to be public if you're placing it on another control.
Hope this helps.

Categories

Resources