Named Xaml Controls are Not Shown in CodeBehind - c#

I use caliburn.micro in WPF.
Although i set x:Name to my element(which is in xaml), i do not see elements (button, textbox, grid etc) in my code behind(In my ViewModel).
As if x:Name is private
For Example:
<Button x:Name="mybutton">
<StckPanel Orientation="Horizontal">
<Image Width="30" Source="/Resources/edit.png" />
<TextBlock Margin="5" FontSize="15" Text="Update">
</TextBlock>
</StackPanel>
</Button>

X:Name doesn't expose your View Elements to ViewModel, in fact, as Clemens rightly pointed out, you shouldn't try to access the View Elements from View Model.
If you are intending to Invoke a method on Button Click (from above xaml) using the Caliburn Micro conventions, you should write a method that corresponds to the x:Name. For example,
public void mybutton()
{
// Do something
}
This would invoke mybutton() method each time your button with x:Name mybutton is clicked.

You cant access your XAML elements with name in ViewModel. You can only access your XAML elements in code behind file only. For example, your XAML is MainWindow.xaml, then you can access XAML elements in MainWindow.xaml.cs file only. The main purpose of applying MVVM pattern to a project is to make view (xaml) and business logic (ViewModel) loosly coupled. Read more about MVVM here.

Related

How can I set custom control binding to parent view model property in Xamarin Forms when using a ListView?

In Xamarin Forms, I defined a custom data template like so:
<DataTemplate x:Key="MyControlDataTemplate">
<ViewCell>
<controls:MyControl/>
</ViewCell>
</DataTemplate>
This snippet belongs to a ListView in MainPage.xaml which has its binding context set to MainPageViewModel.cs
Inside MyControl, I want to bind to a property of MainPageViewModel.
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{set binding here to MainPageViewModel property}" />
</Label.GestureRecognizers>
MainPageViewModel has this command property:
public Command<MyItem> LabelTappedCommand { get; set; }
The idea is to create a single Command object which gets shared between each cell by also setting the CommandParameter property, but I'm stuck with the Command property right now.
Is this possible?
This is certainly possible with 2 easy steps.
Give your xaml page an x:Name=MainPage.
Reference it in the binding like this Command="{Binding Path=BindingContext.MyProperty, Source={x:Reference MainPage}}"
This is under the assumption that the BindingContext of your main page is set to your MainPageViewModel but either way you get the idea.
I think that the only solution is to expose Command binding through the MyControl.cs. After that you can use the solution that references some parent control as the binding context (described in answer by #Knoop and you said you are aware how it works so I am not going into details regarding this).

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 does a WPF window know how to access a nested element?

I have the following working XAML code:
<Window x:Class="DrawShape.Window1"
...
<Grid>
<Polygon Name="poly"/>
</Grid>
</Window>
In the corresponding C# code, a static callback method (for a property called Sides) accesses the poly element as follows:
static void OnSidesChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
Window1 win = obj as Window1;
win.poly.Points.Clear();
...
How is it that poly is accessed directly through Window1 win? poly is nested within a Grid element (albeit nameless). Is this type of access a feature of WPF?
PS: I am aware about the need for access through an object (because the method is static), it is the nesting that I don't understand.
You are confusing the WPF logical tree with how names are handled in XAML. In the logical tree the Polygon is contained in the Grid. However, all names belong to the same scope and are available as fields in the class generated from the XAML.
However, WPF has the concept of Namescopes which makes it possible to use the same name in multiple scopes.
Styles and templates in WPF provide the ability to reuse and reapply content in a straightforward way. However, styles and templates might also include elements with XAML names defined at the template level. That same template might be used multiple times in a page. For this reason, styles and templates both define their own XAML namescopes, independent of whatever location in an object tree where the style or template is applied.
In the simple XAML below you have a Grid named grid containing a ListBox named listBox. In the class generated from the XAML there are fields named grid and listBox allowing the code behind to access both controls.
Each list box item generated by the ItemTemplate contains a TextBlock named textBlock. However, each list box item is in a separate Namescope and there is no field named textBlock in the class generated from the XAML.
<Grid x:Name="grid">
<ListBox x:Name="listBox">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="textBlock" Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
In this simple example there is no need to name the TextBlock objects. However, in more advanced scenarios you may want to refer to named elements within the template, e.g. in triggers.
Locate the file Window1.g.cs in your project directory.
Window1.g.cs contains a partial class that was generated from your XAML. In there you find the variable definition for poly.

WPF Bind to element in parent window

I'm trying to bind element's property in a child control to an element's property ina parent window, it doesn't work..
Here is png of what I'm trying to do:
Here is the xaml that doesn't work:
CurrentDate="{Binding ElementName=TimeBar, Path=SelectionStart,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"
Thanks.
create a dependency property in your usercontrol and then bind to it in your window
something like that: DependencyProperty implementations you can find all around here on stackoverflow
<YourUsercontrol x:Name="uc">
<YourSomeControl CurrentDate="{Binding ElementName=uc, Path=MyDp}"/>
</YourUsercontrol>
xaml window
<Window>
<ElementInParent x:Name="eip" />
<YourUsercontrol MyDp="{Binding ElementName=eip, Path=PropertyFromElementInParent}"/>
based on the following Answer LINK the SelectionStart is not a Bindable Probperty by default so you need to create a attached behavior or something similar
Binding ElementName along with Relative Source is not correct approach.
Besides the UserControl does not know the ElementName of the Parent since the two are in different XAML.
One approach is to set the data context of user control with the element name you want to bind it to and then use normal binding Path.
As shown in the example below:
In main window, we have a textbox and a user control.
We are setting data context of the user control with the text box.
In the user control, we are binding the Text property of the DataContext (which is essentially TextBox of main window).
<Window
xmlns:self="clr-namespace:experiments"
>
<StackPanel>
<TextBox x:Name="Name" Width="100"/>
<self:UserControl1 DataContext="{Binding ElementName=Name}"/>
</StackPanel>
</Window>
<UserControl x:Class="experiments.UserControl1">
<Grid>
<TextBlock Text="{Binding Path=Text}" Width="100" Background="AliceBlue" Height="50"/>
</Grid>
</UserControl>

Binding IsEnabled to the parent ViewModel instead of the UserControl ViewModel

I developed a user control in SilverLight that contains several child controls. Textboxes, ComboBoxes and so on.
The problem is, when I include that UserControl into a parent view and set the complete control to IsEnabled=False, the child controls in that specific UserControl are still enabled.
After all I found the problem.
Adding something like that, implies that the IsEnabled Binding is located in the UserControl binding, not as expected from myself in the DataContext of the parent.
<localControls:TeamEmployeeSelector Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
IsEnabled="{Binding CanModify}" DataContext="{Binding Confidentiality}"/>
QUESTION:
But there's still the question how I can bind the IsEnabled to the ViewModel of the Parent? Because it's not very elegant to copy the CanModify Property to the ViewModel of the Child Control.
Instead of modifying a binding in some way (for example you can make it dependent on other control name as it is proposed in other answer) I would move separate the control which will be disabled and control where DataContext will be changed. For example:
<ContentControl IsEnabled="{Binding CanModify}" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2">
<localControls:TeamEmployeeSelector DataContext="{Binding Confidentiality}"/>
</ContentControl>
Here is how I would do this.
Your TeamEmployeeSelector UserControl will contain a single root level element which by default is a Grid and is given the name "LayoutRoot".
Now you can bind the IsEnabled property of all the child elements to the UserControl like this:-
<TextBox IsEnabled="{Binding Parent.IsEnabled, ElementName=LayoutRoot}" ... />
By using element-to-element binding you do not need to copy the CanModify property in to child view models.
Some might suggest that you simply add an x:Name to your UserControl element and then bind directly to it rather than going via the Parent property of the root element as I do above. That'll work ok in Silverlight 4 but not in 3 or WP7. Personally I prefer the above.
This is a scoping issue. Generally, when creating a UserControl, you want to set itself as the DataContext for its sub-elements. This is most easily accomplished in the constructor:
UserControlExample() {
InitializeComponent();
RootElement.DataContext = this;
}
Where RootElement is the name you give to this first child (usually a Grid or panel) of your UserControl.
From here you can set natural bindings for your sub-elements like so:
<TextBox x:Name="MainTextBox" IsEnabled={Binding IsEnabled} />
This works, since TextBox inherits the DataContext of the parent layout panel.
Finally, if you want to have your UserControl's IsEnabled property to be related to its parent, this is best done at the point of declaration:
<Grid>
<UserControlExample IsEnabled={Binding CanModify} />
</Grid>
This way you keep your concerns separate. The sub-controls don't care what the UserControl is reflecting. They just need to know how to enable/disable when the control's IsEnabled property flips.
sub-controls IsEnabled bound to --> (UserControlExample is DataContext)
UserControlExample.IsEnabled bound to --> (VM is DataContext)
VM.CanModify
I don't know if it's possible in Silverlight, but in WPF I would use RelativeSource.
Have a look here.
Hope this help !
<localControls:TeamEmployeeSelector Grid.Row="1" Grid.Column="0"
Grid.ColumnSpan="2" IsEnabled="{Binding ElementName=SomeElementName_With_Parent_ViewModel, Path=DataContext.CanModify}" DataContext="{Binding Confidentiality}"/>

Categories

Resources