Is there any way to access xaml class reference/name through its child ui control ?
the code is--->
private void AvailableItemListScrollViewer_Loaded(object sender, RoutedEventArgs e)
{
_listScrollViewer = sender as ScrollViewer;
Binding binding = new Binding();
binding.Source = _listScrollViewer;
binding.Path = new PropertyPath("VerticalOffset");
binding.Mode = BindingMode.OneWay;
this.SetBinding(ListVerticalOffsetProperty, binding); <---//(this)
}
Where this (shown above) referring the parent class which contains _listScrollViewer control, but I want to write AvailableItemListScrollViewer_Loaded method for all the pages of my app, so I am putting it into a separate class, but here this listener only receiving that ui element reference, so how can i get the parent class ? So I can write the last line of code above something like this--->
(class reference).SetBinding(ListVerticalOffsetProperty, binding)
Why not to use XAML binding here ? Smth like
<Page ListVerticalOffset="{Binding Path="VerticalOffset"
ElementName="ScrollViewerName"}/>
Simply copy this binding to every page you need with according ElementName
Related
I have several TabControls defined in my XAML. I would like my ViewModel to be aware of the TabItem name or the index of the TabItem that is selected.
I also have a ScrollViewer that i would like to always scroll to the bottom when ever a button is pressed.
I should be able to solve both of the above issues if i could somehow get access to the elements in my code.
How can i acheve something like this:
var tabIndex = this.GetElement<TabControl>("NameOfSomeTabControl").SelectedIndex;
var scrollViewer = this.GetElement<ScrollViewer>("NameOfSomeScrollViewer");
scrollViewer.VerticalScrollBarValue = scrollViewer.VerticalScrollBarMaximum;
Edit: code for xaml, viewModel code
Edit 2:
Looks like i am able to get the instance of the element from the window class, however i'm still not sure how to pass the reference to the ViewModel.
Edit 3: I can achieve the scroll viewer going to the bottom automatically using the code below. however, once that method is invoked it seems like the scrolling gets disabled.
var tbRaw = this.Get<TextBlock>("tbRawOutput");
tbRaw.PropertyChanged += (s,e) => {
var svRaw = this.Get<ScrollViewer>("svRawOutput");
svRaw.Offset = new Vector(svRaw.Offset.X, svRaw.Extent.Height -svRaw.Viewport.Height);};
An easier way to do this might be to use the DataContextChanged event handler in your main Window class:
public MainWindow()
{
InitializeComponent();
DataContextChanged += (object sender, EventArgs wat) =>
{
// here, this.DataContext will be your MainWindowViewModel
};
}
Then you can attach more event handlers/use getters and setters on the view model from the Window
how can I get access to a parent's DataContext?
I've got an UserControl containing 3 buttons, which I want to use for several different UserControls - so the user has always the same actions available.
When clicked on button 'Add' I need to do something inside the current DataContext, which isn't much of a hassle since I can just do the following:
public void CtrlClicked(object sender, RoutedEventArgs e){
Button btn = sender as Button;
MyClass2 c2 = btn.DataContext as MyClass2;
c2.CallCustomMethod();
}
When the button 'Del' is clicked I want to delete the object MyClass2 out of a List<MyClass2> which is held in MyClass1.
In order to do that I need to have access to MyClass1.
My UI (pseudo code):
Window (DataContext = base)
Grid
UserControl uc1 (DataContext = base.MyClass1)
Grid
ListView
ListView.DataTemplate
UserControl uc2 (DataContext = base.MyClass1.MyClass2)
Grid
UserControl ucButtons
Grid
UserControl uc2
ListView.DataTempate
ListView.PanelTemplate
UniformGrid
ListView.PanelTemplate
ListView
Grid
UserControl uc1
Grid
Window
So how can I get access to the MyClass1-objext?
I found out that I can walk the tree using .Parent, but can only do that to a certain point:
Grid gScheduleControlBar = btn.Parent as Grid;
UserControl ucScheduleControlBar = gScheduleControlBar.Parent as UserControl;
Grid gDay = ucScheduleControlBar.Parent as Grid;
UserControl ucDay = gDay.Parent as UserControl;
//ucDay.Name confirms it's the userControl defined
Grid grid = ucDay.Parent as Grid;
// grid.Name="" and grid.Parent = null
so from here there is no further way upwards, which means I can't pass the UserControl 'border'.
Any ideas?
As fallback-option there is of course the way of storing a reference of MyClass1 in MyClass2.
EDIT => Final Result:
<Button x:Name="Del" DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor AncestorType=UserControl AncestorLevel=3}}"
If you want to do this via Bindings, you can use RelativeSource={RelativeSource Mode=FindAncestor AncestorType=yourNamespace:YourType}, from code you can use the VisualTreeHelper to get the visual parent of any control.
If there are multiple parents of that type in your hierarchy can can additionally specify an AncestorLevel. In the example you included, it looks like AncestorType=UserControl and AncestorLevel=2 should work.
I'm trying to create a label at runtime and connect it's Content property to another TextBox control which is in my UserControl called MyLabelSettings.
This is what I got so far:
Label currCtrl = new Label();
MyLabelSettings currCtrlProperties = new MyLabelSettings();
// Bindings to properties
Binding binding = new Binding();
binding.Source = currCtrlProperties.textBox_Text.Text;
binding.Path = new PropertyPath(Label.VisibilityProperty);
BindingOperations.SetBinding(currCtrl.Content, Label.ContentProperty, binding);
The last row shows an error which I did not figure out how to solve:
The best overloaded method match for 'System.Windows.Data.BindingOperations. SetBinding(System.Windows.DependencyObject, System.Windows.DependencyProperty, System.Windows.Data.BindingBase)' has some invalid arguments
I have in MyLabelSettings the implementation of INotifyPropertyChanged
which has the following code when the TexBox.Text changes
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
InvokePropertyChanged(new PropertyChangedEventArgs("TextChanged"));
}
Is there a better way to bind these 2? Or am I doing something wrong in this one?
Thanks!
The problem is simpler than you realize:
This:
binding.Source = currCtrlProperties.textBox_Text.Text;
binding.Path = new PropertyPath(Label.VisibilityProperty);
BindingOperations.SetBinding(currCtrl.Content, Label.ContentProperty, binding);
Should be this:
//The source must be an object, NOT a property
binding.Source = currCtrlProperties;
//Since the binding source is not a DependencyObject, we using string to find it's property
binding.Path = new PropertyPath("TextToBind");
BindingOperations.SetBinding(currCtrl, Label.ContentProperty, binding);
Before, you were attempting to bind the value to an object's property via a property. Now, you're binding the value to an object's property via an object (:
Notes:
You are attempting to bind the text of a control that exists in an instance of a class you just made.
MyLabelSettings currCtrlProperties = new MyLabelSettings();
I base this assumption off this line:
currCtrlProperties.textBox_Text.Text;
Which appears to contain a text control of some sort. Rather, you want bind the text of a property that exists in an instance of a class you make, not a control.
I am quite new to WPF, and especially to DataBinding, and it is pretty hard for me to understand, how to code it without XAML. How can I bind parents visibility (parent is scrollViewer) to its child visibility (child is grid), without XAML? Here is what I am trying to do right now:
{
//Code that creates grid
//Code that creates scrollViewer
scrollViewer.Content = grid;
LayoutRoot.Children.Add(scrollViewer); //adding it to the main window
//Creating binding
Binding myBinding = new Binding("Vis");
BooleanToVisibilityConverter c = new BooleanToVisibilityConverter();
myBinding.Source = grid.Visibility;
myBinding.Converter = c;
myBinding.Mode = BindingMode.TwoWay;
myBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
BindingOperations.SetBinding(scrollViewer, VisibilityProperty, myBinding);
}
And here what is my "Vis" right now:
public Visibility Vis
{
get
{
return Visibility;
}
set
{
Visibility = value;
OnPropertyChanged(Visibility);
}
}
Ofcourse, right now problem is OnPropertyChanged, it gives me an error, and I need to put DependencyPropertyChangedEventArgs inside, but I do not know how to. I am not sure, am I doing this right way (maybe this can be simplified?), or maybe my method will not work at all, even after fixing this error. I need it to be without XAML, because controls are created dynamically.
Solution provided by PieterWitvoet worked for me. I had to set scrollViewer visibility to Visibility.Visible on its creation, but everything else works just fine.
I have a UserControl (Map) that contains a Canvas control. I am dynamically adding a control (Gate) to this canvas from the code behind.
I want the Gate objects DataContext to be the "Gate" property of the Map's DataContext. This is being done in the code behind.
Binding dataContextBinding = new Binding();
dataContextBinding.RelativeSource = new RelativeSource(RelativeSourceMode.Self);
dataContextBinding.Path = new PropertyPath("DataContext.SelectedLevelModule.Gate");
dataContextBinding.Mode = BindingMode.TwoWay;
dataContextBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
BindingOperations.SetBinding(gate, DataContextProperty, dataContextBinding);
After this block of code runs, the gate.DateContext is null...
Any ways this can be done? Drawing a blank..
Thanks
Harold
You are setting the property path to DataContext.SelectedLevelModule.Gate. You are then assigning the binding to the DataContextProperty. I think what is happening is that the path is now gate.DataContext.DataContext.SelectedLevelModule.Gate.
Try removing DataContext from your PropertyPath and see if that fixes it. You are already assigning it to the DataContext, you should not have to specify it in the Path.
var dataContextBinding = new Binding();
dataContextBinding.Path = new PropertyPath("SelectedLevelModule.Gate");
BindingOperations.SetBinding(gate, DataContextProperty, dataContextBinding);