Own user control with new property - c#

I want to create a control like this:
I created view and viewmodel of this control and I added new property - "FileURL".
I want to use this property like this:
<vm:FileSelector FileURL="{Binding Something}"/>
And now it is a problem:
My new control contains button and textbox.
I want that property "FileURL" of FileSelector contains the same value as "Text" of TextBox used inside FileSelector.
So in XAML declaration of new control i wanted to add something like that:
<UserControl x:Class="namespace.FileSelector"
...
FileURL="{Binding ElementName=txtBoxExampleName, Path=Text}">
But this operation is not allowed.
I do not know how can i change value of property "FileURL" inside FileSelector control using MVVM pattern.

Assuming that FileURL is a DependencyProperty in FileSelector then you would just do the following in the FileSelector.xaml:
<TextBox Text="{Binding FileURL, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"/>

Related

"Transfer" a binding from a property to an other

I am trying to wrap a TextBox in a custom UserControl and by then my custom UserControl has a Text dependency property. An example use of the custom UserControl would look like this :
<MyTextBoxWrapper Text="{Binding SomeProperty}"/>
and MyTextBoxWrapper looks like this :
<UserControl ...>
<TextBox x:Name="wrappedTextBox"/>
</UserControl>
I'd like my wrapper to work exactly like if it was written like this :
<UserControl ...>
<TextBox x:Name="wrappedTextBox" Text="{Binding SomeProperty}"/>
</UserControl>
My issue is that I can't manage to "transfer" the binding from the MyTextBoxWrapper.Text property to the TextBox.Text property. (kind of like binding the bindings themselves)
I only managed to obtain the binding used by MyTextBoxWrapper.Text with this :
myTextBoxWrapperInstance.GetBindingExpression(MyTextBoxWrapper.TextProperty);
How can I have the same binding being used for both properties? I don't necessarily need the same binding instance but I at least need the binding used by TextBox.Text to be created from the binding used by MyTextBoxWrapper.Text.
Bind the TextBox in the UserControl to the Text property of the UserControl itself:
<TextBox x:Name="wrappedTextBox"
Text="{Binding Text, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
This doesn't fit my needs, I need to have the binding on TextBox.Text to be the same binding as the one on MyTextBoxWrapper.Text, what you gave me creates a different binding
Yes, a single binding always has a single target and single source.
You may try to register a callback for the custom Text property of the UserControl and programmatically bind the Text property of the TextBox to the same property.
Or make Text a property of type Binding.

Binding to an UserControl's property in a DataTemplate

I have a simple data template in an UserControl composed of a TextBlock and two buttons. The DataContext is set to a list of objects. One button and the TextBlock are bound to properties of that object, but I need one button to be bound to a property of the UserControl.
Can I use RelativeSource to try and find the UC's class, and get the property that way? Something like this:
{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type MyUserControlClass}}, Path=SomeProperty}
At the top of the UserControl give it:
x:Name="MyUserControl"
Then to access the property you can simply use:
"{Binding ElementName=MyUserControl, Path=SomeProperty}"

Set an existing control template as Content Property in WPF Code Behind

I have a very simple XAML
Visibility="Collapsed" X1="1" Margin="-35 0 0 0" Y1="0.4">
<Label.Content>
<Slider Grid.Column="0"
Width="20"
Height="65"
IsDirectionReversed="True"
Maximum="0.1"
Minimum="-4"
Orientation="Vertical"
x:Name="Slider1"
Value="{Binding Source={x:Reference scaleFactorModifier},
Path=ZoomScaleFactor, Mode=TwoWay}" />
</Label.Content>
</Label>
</SciChart:CustomAnnotation.Content>
</SciChart:CustomAnnotation>
Now for some reason I need to set the CustomControl.Content property from code behind. Is there any possibility I move all the label control to some style and template and set the CustomControl content property at runtime with that particular style or template.
Update
Reason for using Code behind
Actually I have Annotations property in my control which could have any control in it as we required. Previously I had used hard coded annotations in my control and placed the controls manually. Now I want to bind the Annotations property. I could create a property of this type and add CustomAnnotation objects in it. But customAnnotation objects need to have labels and other controls in them, how could I do that?
If I have understood your problem correctly, I believe that you can do what you want by using a DataTemplate and a ContentControl. First, define a DataTemplate with your Label in:
<DataTemplate DataType="{x:Type YourPrefix:YourDataType}">
<!-- define your Label here -->
</DataTemplate>
Then you can set the Content property of your CustomControl to a ContentControl that has its own Content property set to an instance of an object of type YourDataType:
<ContentControl Content="{Binding InstanceOfYourDataType}" />
I'm aware that you want to do this programmatically, but that's easy enough to work out:
ContentControl contentControl = new ContentControl();
contentControl.Content = instanceOfYourDataType;
yourCustomControl.Content = contentControl;
I'm wondering if you even really need to use your CustomControl at all, but I'll leave that up to you.
I create a user control from that xaml and then set the CustomControl.Content as new instance of user control. This might not be the best solution, but this is all that I have for now.

How do I avoid binding to 2 datacontext

My application looks like the following
The black is my MainWindow, the red is a tab control and the yellow is a UserControl.
The UserControl has many Dependency Properties defined and they bind to the DataContext (Which is set in the MainWindow's code behind, using this.DataContext = this).
To bind my UserControl to the same DataContext as my MainWindow, in my UserControl xaml I have the following
DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1,AncestorType=Window}}"
This works great, and when I interact with my UserControl, due to the two way binding, it updates the Properties of my MainWindow, which in turn updates my TabControl!
The issue is, my UserControl now has some extra functionality and as such, needs to bind to the UserControl's code behind (such as values for the GUI).
This is where I'm stuck. I can't bind from my UserControl to my code behind because I've already created a DataContext.
I know I could use the WinForms approach, and name each control with x:Name="MyControl" like
MyControl.Text = "This value";
or
MyControl.DataContext = this;
Yeuk I think!!
My question is, is this the only way to go, or can I still use binding.
First of all you don't need to manually set DataContext on UserControl. DataContext is an inheritable property so it will inherit DataContext from its parent unless you have explicitly set it.
Get rid of DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1,AncestorType=Window}}" from your UserControl.
And now, in case you want to bind to code behind for some controls in your UserControl, you can bind using RelativeSource or can set DataContext on control:
DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=UserControl}}"
If controls can be clubbed together under one panel, set DataContext on parent panel say Grid and child controls will inherit from it:
<Grid DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=UserControl}}">
..Child Controls here will inherit DataContext
</Grid>
And to answer your question:
MyControl.DataContext = this; <-- Is this possible
Yes, it is possible like i mentioned above.
You can just use another RelativeSource Binding as you have for the MainWindow properties... to access the properties defined in the UserControl, try the following XAML in your UserControl:
<TextBlock Text="{Binding UserControlProperty, RelativeSource={RelativeSource
AncestorType={x:Type YourXmlNamespacePrefix:YourUserControl}}}" />
Obviously, you'll need to update YourXmlNamespacePrefix:YourUserControl to a valid XML Namespace and control type to get this to work.
I'm not saying either that you should set the DataContext anywhere, or change any properties. This is a RelativeSource Binding... you do not need to set any DataContext to make it work. I thought you would have known that seeing as you're already using one. Just try the example out.

Binding from DependecyProperty to DataContext (ViewModel) in XAML

Assume this situation:
I have created a new control ("MyControl") with DependencyProperty "SuperValue".
Now, in XAML i set "SuperValue" to "TestValue":
<local:MyControl SuperValue="TestValue" />
This control has a ViewModel (DataContext).
I want to pass value of DependencyProperty (in this example "TestValue") to property in ViewModel.
How can I do this?
Assume that ViewModel of my control do something calculations, for example: User inputs name of country, and control give him a time which is currently there.
The problem is: How can I provide the result of calculation? Assume that this is public property "Results" in ViewModel. I want to create a property like "TextBox.Text", "ListView.SelectedItem" which provides a part of ViewModel data "to outside".
For example TextBox and Text property:
<TextBox Text={Binding GiveMeTextValue} />
In this case DP "Text" provides to outside a ViewModel property which currently stores inputted text.
I want to use my control in the same way.
I don't know whether I get your question right: You want to set a static non-bound value in XAML to a DependencyProperty of the control and set a property on the control's DataContext to this static value? There is something wrong about your concept if you need to do this, why don't you provide this value on the ViewModel in an according field and bind the DP of the control to this field?
However, what you can do get what you want:
Define a PropertyChangedCallback when you register the DP:
// Dependency Property
public static readonly DependencyProperty TestProperty =
DependencyProperty.Register("Test", typeof(string),
typeof(MyControl), new FrameworkPropertyMetadata("123", new PropertyChangedCallback(OnTestChanged)));
In the OnTestChanged method, cast your DataContext to the type of your ViewModel and set the according value on the ViewModel to the new value:
private static void OnTestChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MyControl c = d as MyControl;
ViewModelType vm = c.DataContext as ViewModelType;
vm.Property = e.New;
Console.WriteLine(e.NewValue);
}
Is that what you're asking for?
What about setting the MyDependencyProperty from the setter of property SomethingValueInDataContext.
EDIT
You can set the controls DependencyProperty where the control is used and not on its declaration. This will work (local is namespace where control resides) -
<Grid>
<local:MyOwnControl MyDependencyProperty="{Binding Test}"/>
</Grid>
Same as like you can set the Width of the TextBox when you create an instance of it in xaml like this-
<TextBox Width="{Binding PropertyName}"/>
Notice, the root of your xaml is UserControl and not MyOwnControl. UserControl is the base class of MyOwnControl; your property is not defined in the base class. This is why you cannot reference MyDependencyProperty from within the root element of the UserControl.
Using your example, you can switch the binding and get your desired effect.
<UserControl
x:Class="namespace.MyOwnControl"
x:Name="root">
<UserControl.DataContext>
<local:ControlViewModel
Test={Binding MyDependencyProperty, ElementName=root}" />
</UserControl.DataContext>
</UserControl>
Since you are using a MVVM design paradigm all data should be relative to the ViewModel. So your DP should be set via the binding in your VM property.
If the test data is going to be used in Blend/VS designer you can check for that vs. Debug/Release... then do some sort of assignment to your property based off of that check for testing.
You could add a property to MyControl called InitialSuperValue that when set, sets the value of SuperValue. Then write some XAML like this:
<local:MyControl InitialSuperValue="TestValue" SuperValue="{Binding SuperValueInViewModel, Mode=OneWayToSource}" />

Categories

Resources