Create a simple UserControl - c#

i'm trying to create a simple Windows Store App.
I want to reuse some "code" in many pages.
For example i need to reuse someting like this in more than one page..
<StackPanel>
<TextBlock Text="Name"/>
<TextBox x:Name="edtNome"/>
Maybe the best method is using "UserControl"...but i can't realize how!
i've created mine MyUC.xaml
<UserControl
x:Class="Crud.View.MyUC"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Crud.View"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid>
<StackPanel>
<TextBlock Text="Name"/>
<TextBox x:Name="edtName"/>
</StackPanel>
But now?
I want to put it in my Page.xaml (and in many other), and access the "edtName" from page.xaml code behind.....
what i have to do?

Something like this
in xaml use a binding path. Add an x:Name for your control. ElementName=me 'me' will be the name given to your control
<TextBox x:Name="edtName" Text="{Binding Path=EditName, ElementName=me, Mode=Default}" ..../>
in that code behind add
public string EditName
{
get { return (string)GetValue(EditNameTextProperty); }
set { SetValue(EditNameTextProperty, value); }
}
public static readonly DependencyProperty EditNameTextProperty =
DependencyProperty.Register("EditName",
typeof(string),
typeof(YourClassNameHereForThisControl),
new FrameworkPropertyMetadata(""));

Related

WPF command bindings in user controls not working

I've tried pretty hard to find a solution by myself searching the web and following examples but everything I've tried until now has failed. I know that my poor experience with WPF is making me missing something huge and silly but as a matter of fact I'm stuck.
As written in the object, I have a custom UserControl that contains a RadioButton. I want to 'expose' the Command of the RadioButton outside through a DependencyProperty of my UserControl.
The .xaml of the UserControl (named 'ImageRadioButton') is the following:
<UserControl x:Class="WpfSinergoHMIControls.Controlli.ImageRadioButton"
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"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
</UserControl.Resources>
<Grid>
<Grid>
<RadioButton Command="{Binding SomeCommand, ElementName=me}" Name="button1" Foreground="White">
</RadioButton>
</Grid>
</Grid>
</UserControl>
the dependency property in the UserControl program file is the following:
public static readonly DependencyProperty SomeCommandProperty =
DependencyProperty.Register(
"SomeCommand",
typeof(ICommand),
typeof(ImageRadioButton),
new UIPropertyMetadata(null));
public ICommand SomeCommand
{
get { return (ICommand)GetValue(SomeCommandProperty); }
set { SetValue(SomeCommandProperty, value); }
}
Finally I declare in the application that uses my UserControl an istance:
<Controlli:ImageRadioButton x:Name="btnAutomatic" GroupName="MainMenu" SomeCommand="{Binding DataContext.NavigateAutomaticCommand, ElementName=MainViewObj}" HorizontalAlignment="Left" Height="60" VerticalAlignment="Bottom" Width="140" Canvas.Left="1373" Canvas.Top="5" Margin="6,0,0,5" IsChecked="True"/>
worthless to say that this doesn't work (no command is called). I know that there is something silly that I'm missing but after a lot of trials/searching I still cannot find the solution.
Thanks!
You reference the element me in your command binding, but you do not assign that name anywhere, which means that the binding source (your UserControl) cannot be found at runtime.
Command="{Binding SomeCommand, ElementName=me}"
If you set the name on your UserControl everything works as expected (at least for me).
<UserControl x:Class="WpfSinergoHMIControls.Controlli.ImageRadioButton"
...
x:Name="me">

Why is an image resource in a class library not loaded?

I have strange problem, which I don't know how to find - I looked for similair posts here, but failed.
Problem is that I have custom control in WPF and, obviously, I want to reuse it in multiple projects.
I have image background in that control with label over it (assured with Panel.ZIndex).
In one project it is showing correctly, but in another just Label is showing, image for some reason does no display.
What could problem be? I am loosing my mind over this...
Below code of a control:
<UserControl x:Class="SampleControls.LabelWithBoxBackground"
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"
xmlns:local="clr-namespace:SampleControls"
mc:Ignorable="d"
d:DesignHeight="150" d:DesignWidth="400" x:Name="labelWithBoxBackground">
<Grid>
<Image Source="pack://application:,,,/Images/boxImage.png" Stretch="Fill" Panel.ZIndex="1"/>
<TextBlock Background="White" Text="{Binding ElementName=labelWithBoxBackground, Path=Text}" Margin="0,20,0,0" Panel.ZIndex="2" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Bold" FontFamily="Calibri"/>
</Grid>
</UserControl>
Code behind:
public partial class LabelWithBoxBackground : UserControl
{
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(LabelWithBoxBackground), new FrameworkPropertyMetadata(string.Empty));
public string Text
{
get { return GetValue(TextProperty).ToString(); }
set { SetValue(TextProperty, value); }
}
public LabelWithBoxBackground()
{
InitializeComponent();
}
}
Use a full Resource File Pack URI, including the assembly name (not the namespace) of your UserControl library, as shown below.
Otherwise WPF resolves the Pack URI with the name of the "local" assembly, which may be that of the main application.
Source="pack://application:,,,/SampleControls;component/Images/boxImage.png"
Also make sure that the Build Action of the image file is set to Resource.
As a note, setting Panel.ZIndex is pointless here. The elements are stacked by default in the order they are declared in XAML, so the TextBlock is always on top of the Image, even without setting ZIndex.

mvvm light calling RaisePropertyChanged doesn't fire Property getter(windows phone 8.1)

in my application I have a textbox that user type a number on it. I want to this Latin number to Persian one as user type it. after calling RaisePropertychanged the getter of MobileNumber not called so App Ui doesn't update. what is the problem with my code?
here is my code
View.xaml
<Page
x:Class="CustomName.RegistrationPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ShahrMobileBank.Views.Masters.Registration"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:behaviors="using:Template10.Behaviors"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:converter="using:ShahrMobileBank.Converter"
mc:Ignorable="d"
DataContext="{Binding Path=RegistrationPage, Source={StaticResource ViewModelLocator}}">
<StackPanel Background="{StaticResource RegistrationPageBackgroundColor}" x:Name="LayoutRoot">
<StackPanel.Resources>
<converter:RegistrationConverter x:Key="RegistrationConverter"/>
</StackPanel.Resources>
<TextBox Style="{StaticResource GenericTextBoxBeforeLogin}" x:Uid="PhoneNumber" InputScope="Number" Text="{Binding Path=MobileNumber, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" MaxLength="{StaticResource MobileNumberMaxLength}"/>
</StackPanel>
</Page>
ViewModel.cs
public class RegistrationPageViewModel : ViewModelBase
{
private string _mobileNumber;
public String MobileNumber
{
get
{
return _mobileNumber;
}
set
{
_mobileNumber = LangUtil.ConvertEnNumberToFaNumber(value); // this converts the number from Latin to Persian
RaisePropertyChanged(() => MobileNumber);
}
}
}
Try changing the RaisePropertyChanged line to RaisePropertyChanged("MobileNumber");
If you use the MVVM-Light Code snippets (if installed, you can start typing mvvm, and intellisense will pop up), you can look at mvvmpinpcwhich is one of the PropertyChanged code snippets. You can Tab through the different template fields to set it up to what you want, as well as possibly shed any light on little tips and tricks to make your coding life easier.

Change between pages in WPF

I want to make a layout like the one used in any website - the header, sidebar and footer stay the same but the center part. I have multiple pages/windows to show in a wpf blend C# application and they are totally different. For example, stackoverflow has a layout for the homepage and another one for each Question. Here's another exemple:
I had to do that in a previous project and I used a single grid layout and then, for each page, I had to hide() all of them and show that each one on top -
What's the trick? How can I do the same thing in a wpf application? In a typical C# application I would have to open a child window each time but that seems ugly these days.
Thank you in advance!
If you are going to use Pages in WPF, then you will need to read the Navigation Overview page on MSDN. In short however, you can navigate between Pages in a WPF Application by using the NavigationService Class. To change the page from code behind, you could do something like this:
NextPage page = new NextPage();
NavigationService.Navigate(page);
To let the users change the Page, you can use the Hyperlink Class in your Pages:
<Hyperlink NavigateUri="pack://application:,,,/AppName;component/Pages/NextPage.xaml">
Navigate to Next Page
</Hyperlink>
To get your desired page setup, you will have to load your Pages into a Frame, which you can then layout wherever you like in MainWindow.xaml:
<Frame Source="pack://application:,,,/AppName;component/Pages/SomePage.xaml" />
Sounds like you need a custom usercontrol and some databinding.
You can declare DataTemplates in XAML as resources with the model type as key, so that WPF chooses the correct DataTemplate automatically:
Have a main ViewModel, which exposes a ImageSourceViewModel property. This property would either return a CameraSourceViewModel or a FileSourceViewModel, as appropriate.
In your page, the DataContext would be the main ViewModel, and you'd have XAML like this:
Then,
<Page x:Class="Page1"
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"
xmlns:my="clr-namespace:WpfApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="Page1">
<Page.Resources>
<DataTemplate DataType="{x:Type my:CameraSourceViewModel}">
<my:CameraSourceView/>
</DataTemplate>
<DataTemplate DataType="{x:Type my:FileSourceViewModel}">
<my:FileSourceView/>
</DataTemplate>
</Page.Resources>
<Grid>
<ContentControl Content="{Binding ImageSourceViewModel}"/>
</Grid>
I should point out that this example uses the MVVM pattern to allow the viewmodel layer to decide on the content in the middle. Hopefully this is clear enough, if not, give me a shout and I'll try to expand it!
Let's say I have main view model where I've created a CurrentPage property that will tell which page you want to display.
/// <summary>
/// Returns the page ViewModel that the user is currently viewing.
/// </summary>
public ViewModelBase CurrentPage
{
get { return _currentPage; }
private set
{
if (value != _currentPage)
{
if (_currentPage != null)
_currentPage.IsCurrentPage = false;
_currentPage = value;
if (_currentPage != null)
_currentPage.IsCurrentPage = true;
RaisePropertyChanged(() => CurrentPage);
}
}
}
And in your xaml you can bind your page under some control. Let's say I am doing it inside a Border element.
<!-- CURRENT PAGE AREA -->
<Border Background="White" Grid.Column="1" Grid.Row="0">
<HeaderedContentControl Content="{Binding Path=CurrentPage}"
Header="{Binding Path=CurrentPage.DisplayName}" />
</Border>
You can define view to your view model in resources just like this:
(partially complete XAML)
<UserControl x:Class="BAT.View.BATWizardView"
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"
xmlns:view="clr-namespace:BAT.View"
xmlns:viewmodel="clr-namespace:BAT.ViewModel"
mc:Ignorable="d"
d:DesignHeight="350" d:DesignWidth="600">
<UserControl.Resources>
<!-- These four templates map a ViewModel to a View. -->
<DataTemplate DataType="{x:Type viewmodel:MyComparisonViewModel1}">
<view:MyView1 />
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodel:MyComparisonViewModel2}">
<view:MyView2 />
</DataTemplate>
</UserControl.Resources>
<Grid>
<Border Background="White" Grid.Column="1" Grid.Row="0">
<HeaderedContentControl Content="{Binding Path=CurrentPage}"
Header="{Binding Path=CurrentPage.DisplayName}" />
</Border>
</Grid>
</UserControl>
See if that helps.

View is not being resolved with Toolbar ItemsSource

It doesn't seem like the Caliburn Micro framework is retrieving my SinglePaintToolbarView when it is binded as a list of buttons in the toolbar of the ShellView. I would like the buttons to just display their text content when they are added to the toolbar. But, instead I'm getting this:
There doesn't appear to be any clickable buttons in the toolbar. I know my plugins are being loaded successfully, because I was able to bind one of the plugins in the list as a ContentControl and the view appeared. It just doesn't seem to work when I try to bind a list of the plugins in a toolbar.
Here is what I have:
ShellView.xaml
<UserControl x:Class="Starbolt.Views.ShellView"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<ToolBarTray>
<ToolBar ItemsSource="{Binding Path=ToolbarPlugins}"/>
</ToolBarTray>
</Grid>
</UserControl>
ShellViewModel.cs
[Export(typeof(IShell))]
public class ShellViewModel : PropertyChangedBase, IShell
{
[ImportMany(typeof(IToolbarPlugin))]
private IEnumerable<IToolbarPlugin> _toolbarPlugins = null;
public IEnumerable<IToolbarPlugin> ToolbarPlugins { get { return _toolbarPlugins; } }
}
SinglePaintToolbarView.xaml
<UserControl x:Class="Starbolt.Plugin.SinglePaintTool.Views.SinglePaintToolView"
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"
mc:Ignorable="d"
d:DesignHeight="128" d:DesignWidth="32">
<Button Name="btnSinglePaintTool" Content="Single Paint Tool" Width="128" Height="32"/>
</UserControl>
SinglePaintToolViewModel.cs
[Export(typeof(IToolbarPlugin))]
public class SinglePaintToolViewModel : IToolbarPlugin
{
}
Basically, your design seems to be working. If you replace
<ToolBarTray>
<ToolBar x:Name="ToolbarPlugins"/>
</ToolBarTray>
(note that you do not need to bind the ItemsSource explicitly, you can just as well use the Caliburn Micro property name conventions) with the following:
<ListBox x:Name="ToolbarPlugins"/>
the SinglePaintToolView button is displayed as intended.
I suspect that the problem is with the ToolBar ControlTemplate, which most certainly restricts the toolbar items layout more than what for example a ListBox ControlTemplate does.
So my guess is that if you really want to use the ToolBar control to display your IToolbarPlugin views, you will probably have to design a dedicated ToolBar control template in your project.
Alternatively, you could implement a toolbar replacement using e.g. ListBox. This could be a start:
<ListBox x:Name="ToolbarPlugins">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>

Categories