In my UserControl i have drawn some paths inside canvas
In order to open a control panel for this UserControl I used InputBindings like this :
<UserControl.InputBindings>
<MouseBinding Gesture="LeftClick" Command="{Binding OpenControlPanelCommand}"/>
</UserControl.InputBindings>
This is working only when I click on the paths that I have drawn. Actually I want all the UserControl's surface be clickable not only the drawn part
I set the background of the usercontrol but it doesn't working
How can I change this behavior ?
This works for me:
<UserControl …
Background="Transparent"
>
<UserControl.InputBindings>
<MouseBinding Gesture="LeftClick" Command="{Binding OpenControlPanelCommand}"/>
</UserControl.InputBindings>
<Canvas>
<Path Data="M0,0L25.194,16 0,32z" Stretch="Fill"
Height="100"
Width="100"
Fill="Black"/>
</Canvas>
</UserControl>
I have it in a window:
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<local:UserControl1/>
</Grid>
Relevant part of vm:
using …
using GalaSoft.MvvmLight.CommandWpf;
namespace wpf_99
{
public class MainWindowViewModel : INotifyPropertyChanged
{
public ICommand OpenControlPanelCommand { get; set; } = new RelayCommand(() => MessageBox.Show("Hello World"));
Is your usercontrol filling the area you're expecting it to?
Is your command binding correctly?
Anything on top of it that's grabbing the click?
Related
I have a usercontrol which contains an ellipse inside the Canvas. I am using this control in another window and when i set the background color, i want to change only the background of ellipse.How to change the ellipse(child) background without changing canvas(parent) background color?
1. Add a DependencyProperty to the code-behind of your MyUserControl.
Note the 3rd parameter of the Register method is whatever the Type name is of your UserControl
public Brush EllipseFill
{
get { return (Brush)GetValue(EllipseFillProperty); }
set { SetValue(EllipseFillProperty, value); }
}
public static readonly DependencyProperty EllipseFillProperty =
DependencyProperty.Register("EllipseFill", typeof(Brush), typeof(MyUserControl), new PropertyMetadata(null));
2. Add a reference to the xaml file of both the main Window and the UserControl for the namespace where MyUserControl is defined :
xmlns:local="clr-namespace:WpfApplication1"
3. Bind the Fill property of your Ellipse to the dependency property that was defined on MyUserControl.
Note the use of MyUserControl in AncestorType parameter of the RelativeSource binding.
<Viewbox>
<Canvas Width="100" Height="100">
<Ellipse Width="50"
Height="20"
Canvas.Top="50"
Canvas.Left="50"
Fill="{Binding Path=EllipseFill,
RelativeSource= {RelativeSource Mode=FindAncestor,
AncestorType={x:Type local:MyUserControl}}}"
/>
<Rectangle Width="20"
Height="40"
Canvas.Top="10"
Canvas.Left="10"
Fill="Blue"
/>
</Canvas>
</Viewbox>
4. Set the EllipseFill property on MyUserControl in the main Window
<local:MyUserControl EllipseFill="Red"/>
I have an User control. That UserControl have some functionalities. I have called this usercontrol in my Common Resource Directory file. I am Inherit this Resource Directory page in all pages. This enables my user control in all my pages. what i want is, I want this usercontrol for Some particular page which i can set. This is my code.
Resource Directory file:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:UserControls">
<!-- Navigation AppBar -->
<l:NavigationAppBarUserControl
Grid.Row="1" Grid.Column="0" Width="100"
HorizontalAlignment="Left" Visibility="Visible" />
</ResourceDictionary>
Window1.xaml:
<src:WindowBase x:Class=""
xmlns:src="clr-namespace:ProjectOne"
Title="Window1">
<Grid>
//some functions...
</Grid>
</src:WindowBase>
This will enable my user control. But this page, i want to hide my user conrol. But without removing (src:WindowBase).. how can i hide the UserControl here? Any help would be appriciated. Thanks in advance..
In WindowBase class create a property of type Visibility and bind the Visisbility of UserControl to it.
WindowBase
public class WindowBase : Window
{
public WindowBase(Visibility ucVisibility)
{
UCVisibility = ucVisibility;
}
public WindowBase() : this(Visibility.Visible) { }
public Visibility UCVisibility { get; set; }
//other stuff
}
UC binding
<l:NavigationAppBarUserControl
Grid.Row="1" Grid.Column="0" Width="100"
HorizontalAlignment="Left"
Visibility="{Binding UCVisibility, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}" />
Now where you do not want it to show send Visibility.Collapsed in base constructor.
public partial class Window3 : WindowBase
{
public Window3():base(Visibility.Collapsed)
{
InitializeComponent();
}
}
I hope this will help.
I have ObservableCollection Fathers which contains property ObservableCollection Sons.
And I'm displaying it on the TreeView setting its DataContext property.
The Sons property displays as a ListBox of radio button under each Father - binded to ItemsSource.
First time setting the DataContext of the tree view to the fathers list, everything is working good. The radio buttons are checked according to the data.
Now, I'm setting the TreeView.DataContext to null - so the data will disappear. and then back to the original Fathers ObservableCollection which I set in the first time.
And now from some reason the radio buttons stopped being synchronized with the son object.
And I got deeper and I saw that the setter in the son object (that binded to the radio button) is raised with false from some reason. I Guess something related to the binding.
Is there any cache that the TreeView, or the ObservableCollection is saving after binding ? I want it to work like the first time I set the bind - Which there like it should only the getter is being called like it should.
Thanks.
This is my Tree view
<UserControl x:Class="Tester.CTLMyTree"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<Border Background="#FF919191" BorderThickness="1" CornerRadius="5"
HorizontalAlignment="Left" VerticalAlignment="Top"
Padding="5" BorderBrush="Black" Height="207" Width="190">
<Border.Resources>
<sdk:HierarchicalDataTemplate x:Key="LayerListTemplate">
<StackPanel Orientation="Vertical" Width="200" >
<TextBlock Text="Hello"/>
<ListBox x:Name="lstViews" ItemsSource="{Binding Sons}" BorderThickness="0" Width="200">
<ListBox.ItemTemplate>
<DataTemplate>
<RadioButton Content="Check" IsChecked="{Binding IsChecked, Mode=TwoWay}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</sdk:HierarchicalDataTemplate>
</Border.Resources>
<sdk:TreeView ItemsSource="{Binding}" ItemTemplate="{StaticResource LayerListTemplate}" x:Name="myTreeView" />
</Border>
</Grid>
</UserControl>
The Objects behind
public class CCFather
{
public CCFather()
{
Sons = new ObservableCollection<CCSon>();
}
public ObservableCollection<CCSon> Sons
{
get;
set;
}
}
public class CCSon
{
private bool m_blnChecked;
public bool IsChecked
{
get
{
return m_blnChecked;
}
set
{
m_blnChecked = value;
}
}
}
In my application i added this treeview control and called it m_objSimpleTree.
This code is the initializing
m_objItems = new ObservableCollection<CCFather>();
CCFather objItem1 = new CCFather();
objItem1.Sons.Add(new CCSon());
objItem1.Sons[0].IsChecked = true;
m_objItems.Add(objItem1);
m_objSimpleTree.myTreeView.DataContext = m_objItems;
And when i press a button i'm doing this
m_objSimpleTree.myTreeView.DataContext = null;
m_objSimpleTree.myTreeView.DataContext = m_objItems;
This code will raise already the IsChecked setter of the son to false (Why ???)
But the RadioButton will still be checked.
Second time pressing the button. it will be unchecked and the setter didn't raise.
When i'm pressing on the radio button It's raising twice the setter. First time with false
second with true.
Can't figure why it's happening.. The only think i can think of is that the treeview is saving something in the first binding or something like this.
It does so because you have used twoWay binding for the control
binding code project
In a two way binding when you change some thig on the view then the data gets saved in the object also . to which the datacontext is assigned. try oneWay for that . But need to be careful as if you wanna save data using twoWay one way might not help. MVVM suggests to use two way binding to save data but you want a refreshed list then create a new object :)
Also try clear Binding
Clear binding
Am not sure of the last link as never tried. Please o through it might get an idea. But since you might need a new object again so you can create a fresh object to assign to datacontext.
--- EDIT-----
Here's a xaml code
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" x:Class="SilverlightSOApp.MainPage"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<Border Background="#FF919191" BorderThickness="1" CornerRadius="5"
HorizontalAlignment="Left" VerticalAlignment="Top"
Padding="5" BorderBrush="Black" Height="207" Width="190">
<Border.Resources>
<sdk:HierarchicalDataTemplate x:Key="LayerListTemplate">
<StackPanel Orientation="Vertical" Width="200" >
<TextBlock Text="Hello"/>
<ListBox x:Name="lstViews" ItemsSource="{Binding Sons}" BorderThickness="0" Width="200">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<RadioButton Content="Check" GroupName="abcd" IsChecked="{Binding IsChecked, Mode=TwoWay}"/>
<RadioButton Content="Check" GroupName="abcd" IsChecked="{Binding IsChecked2, Mode=TwoWay}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</sdk:HierarchicalDataTemplate>
</Border.Resources>
<sdk:TreeView ItemsSource="{Binding}" ItemTemplate="{StaticResource LayerListTemplate}" x:Name="myTreeView" />
</Border>
<Button Content="Button" HorizontalAlignment="Left" Margin="303,268,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
And the c#
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace SilverlightSOApp
{
public partial class MainPage : UserControl
{
private ObservableCollection<CCFather> m_objItems;
public MainPage()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
m_objItems = new ObservableCollection<CCFather>();
CCFather objItem1 = new CCFather();
objItem1.Sons.Add(new CCSon());
objItem1.Sons[0].IsChecked = false;
m_objItems.Add(objItem1);
myTreeView.DataContext = m_objItems;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
myTreeView.DataContext = null;
myTreeView.DataContext = m_objItems;
}
}
public class CCFather
{
public CCFather()
{
Sons = new ObservableCollection<CCSon>();
}
public ObservableCollection<CCSon> Sons
{
get;
set;
}
}
public class CCSon
{
private bool m_blnChecked;
private bool m_blnChecked2;
public bool IsChecked
{
get
{
return m_blnChecked;
}
set
{
m_blnChecked = value;
}
}
public bool IsChecked2
{
get
{
return m_blnChecked2;
}
set
{
m_blnChecked2 = value;
}
}
}
}
Now the main point if you want to implement it for single radio button then you need to implement the Click event and set radio button to false and next time to true :) or else you need to use a checkbox one radio button once checked cannot be converted to false
I'd better ask the question by example. Let's say I have UserControl and Window which uses this control.
I would like to design this control (named MyControl) in such way (this is sci-fi syntax!):
<Grid>
<Button>Just a button</Button>
<PlaceHolder Name="place_holder/>
</Grid>
and use in such ways when designing my Window:
<MyControl/>
or
<MyControl>
<place_holder>
<Button>Button 1</Button>
</place_holder>
</MyControl>
or
<MyControl>
<place_holder>
<Button>Button 1</Button>
<Button>Button 2</Button>
</place_holder>
</MyControl>
Of course I would like to have ability to add even more elements to MyControl in Window. So, in a way it should work as container (like Grid, StackPanel, and so on). The placement would be defined in UserControl (in this example after button "Just a button") but what to add (what elements) would be defined in Window (where UserControl -- MyControl -- is used).
I hope this is clear what I would like to achieve. The key point is using XAML when designing Window, so my class should be no worse than other controls.
Now, the big QUESTION is -- how to do it?
Remarks: styling is out of scope. All I want to do is add any controls I want to MyControl when designing Window (not when designing MyControl).
ContentControls & ItemsControls are good for this, you can bind them to a property of your UserControl or expose them.
Using a ContentControl (for placeholders in multiple disconnected places):
<UserControl x:Class="Test.UserControls.MyUserControl2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
Name="control">
<Grid>
<Button>Just a button</Button>
<ContentControl Content="{Binding PlaceHolder1, ElementName=control}"/>
</Grid>
</UserControl>
public partial class MyUserControl2 : UserControl
{
public static readonly DependencyProperty PlaceHolder1Property =
DependencyProperty.Register("PlaceHolder1", typeof(object), typeof(MyUserControl2), new UIPropertyMetadata(null));
public object PlaceHolder1
{
get { return (object)GetValue(PlaceHolder1Property); }
set { SetValue(PlaceHolder1Property, value); }
}
public MyUserControl2()
{
InitializeComponent();
}
}
<uc:MyUserControl2>
<uc:MyUserControl2.PlaceHolder1>
<TextBlock Text="Test"/>
</uc:MyUserControl2.PlaceHolder1>
</uc:MyUserControl2>
ItemsControl-Version (for collections in one place)
<UserControl x:Class="Test.UserControls.MyUserControl2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
Name="control">
<Grid>
<Button>Just a button</Button>
<ItemsControl Name="_itemsControl" ItemsSource="{Binding ItemsSource, ElementName=control}"/>
</Grid>
</UserControl>
[ContentProperty("Items")]
public partial class MyUserControl2 : UserControl
{
public static readonly DependencyProperty ItemsSourceProperty =
ItemsControl.ItemsSourceProperty.AddOwner(typeof(MyUserControl2));
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public ItemCollection Items
{
get { return _itemsControl.Items; }
}
public MyUserControl2()
{
InitializeComponent();
}
}
<uc:MyUserControl2>
<TextBlock Text="Test"/>
<TextBlock Text="Test"/>
</uc:MyUserControl2>
With UserControls you can decide to expose certain properties of internal controls; besides the ItemsSource one probably would want to also expose properties like the ItemsControl.ItemTemplate, but it all depends on how you want to use it, if you just set the Items then you do not necessarily need any of that.
I think you want to set your UserControl's ControlTemplate with a ContentPresenter located inside (so you can define where the Content will be presented).
Your Custom UserControl:
<UserControl x:Class="TestApp11.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Template>
<ControlTemplate>
<StackPanel>
<TextBlock Text="Custom Control Text Area 1" />
<ContentPresenter Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}" />
<TextBlock Text="Custom Control Text Area 2" />
</StackPanel>
</ControlTemplate>
</UserControl.Template>
</UserControl>
Usage:
<Window x:Class="TestApp11.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:TestApp11"
Title="Window1" Height="250" Width="200">
<StackPanel>
<l:UserControl1>
<Button Content="My Control's Content" />
</l:UserControl1>
</StackPanel>
</Window>
If you need multiple items in your content section, simply place them in a container like a grid or a stackpanel:
<l:UserControl1>
<StackPanel>
<Button Content="Button 1" />
<Button Content="Button 2" />
</StackPanel>
</l:UserControl1>
I have created a Silverlight User Control. The markup is:
<StackPanel Grid.Row="4" Grid.Column="0" Orientation="Horizontal" Width="Auto" Margin="5">
<Button Content="OK" Margin="0,0,5,5" MinWidth="50" Command="{Binding OKCommand}" />
</StackPanel>
The code behind declares a Dependency property 'OKCommand' as:
public ICommand OKCommand
{
get
{
return (ICommand)GetValue(OKCommandProperty);
}
set
{
SetValue(OKCommandProperty, value);
}
}
public static readonly DependencyProperty OKCommandProperty
= DependencyProperty.Register("OKCommand", typeof(ICommand), typeof(TestUserControl), new PropertyMetadata(null, OKCommandProperty_PropertyChangedCallback));
private static void OKCommandProperty_PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
Now I want to use the user control on another page where which is the View & the ViewModel defines the command to which I want the OKCommand to be bound. The XAML markup is as such:
<local:TestControl OKCommand="{Binding Path=TestControlOk}"/>
However when I click the button it does not execute anything. Any clues as to what I am doing wrong here.
You need to show the view model that contains the TestControlOk property so we can tell if that's part of the problem.
UserControls do not register themselves as the data context automatically so the binding inside the user control won't have anything to bind to. Do you have
this.DataContext = this;
anywhere in the UserControl codebehind to enable your first binding to actually work?
Alternatively, you can do something like so:
<UserControl .....
x:Name="MyUserControl">
<StackPanel Grid.Row="4" Grid.Column="0" Orientation="Horizontal" Width="Auto" Margin="5">
<Button Content="OK" Margin="0,0,5,5" MinWidth="50"
Command="{Binding OKCommand, ElementName=MyUserControl}" />
</StackPanel>
</UserControl>
Note the ElementName= part of the binding pointing to the root UserControl element in your XAML.