The Issue: I have a newly made UserControl with a couple telerik controls in a parent Grid to be able to use it throughout the solution. Sounds simple enough right? I created the UserControl, let's call the Class My.Project.Controls.Tool, which I then tried to call to another View with the namespace xmlns:Controls="clr-namespace:My.Project.Controls;assembly=My.Project.GlobalUserControlDump" and then set it in the view via easily selected from the handy dandy intellisense.
This does as is expected, my UserControl appears on the separate view in the designer just fine. So I take the next normal step and build it....as soon as the build completes (which it does just fine with no errors reported as expected) the little bugger disappears! The xaml is still on the View of course, but it's disappeared from the designer AND it doesnt appear on the built solution?
Confused I go back, make a quick change to the UserControl and it appears back in the designer. Ok, I think it must be some fluke so I build it again....and again it disappears from the designer AND the built solution?
Now I can continue to reliably reproduce this scenario. Make a little change to the UserControl, it re-appears in the designer.....then build it and it disappears again!
Could someone pretty please shed some light on this quandry? Running in SL (both in and out of browser but built in browser) with Caliburn Micro. Any insight to this mystery is of course greatly appreciated, hoping another pair of eyes can catch my folly. Cheers!
For Clarification, this is what sits in the user control that directly related to a previous question.
<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:telerik="http://schemas.telerik.com/2008/xaml/presentation"
mc:Ignorable="d"
x:Class="My.Project.Controls.DatePicker">
<Grid Width="90">
<telerik:RadDateTimePicker
InputMode="DatePicker"
SelectedDate="{Binding SelectedDate, Mode=TwoWay}"/>
<telerik:RadMaskedDateTimeInput
IsClearButtonVisible="False"
FormatString="{}{0:M/d/yy}"
SelectionOnFocus="SelectAll"
Value="{Binding SelectedDate, Mode=TwoWay}"/>
</Grid>
</UserControl>
Which I would then invoke directly on a view like (It would sit in the GlobalUserControlDump project as the namespace shows) and once the namespace is added to the View, it shows up fine in the intellisense as expected;
<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:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
x:Class="My.Project.Views.RandomView"
xmlns:Controls="clr-namespace:My.Project.Controls;assembly=My.Project.GlobalUserControlDump"
mc:Ignorable="d">
<Grid>
<Controls:DatePicker />
</Grid>
</UserControl>
Then I'm exposing the property I need via;
namespace My
{
public partial class DatePicker : UserControl
{
public static readonly DependencyProperty SelectedDateProperty =
DependencyProperty.Register("SelectedDate", typeof(DateTime), typeof(DatePicker), new PropertyMetadata(null));
public DatePicker()
{
// Required to initialize variables
DataContext = this;
}
public DateTime SelectedDate
{
get { return (DateTime)GetValue(SelectedDateProperty); }
set { SetValue(SelectedDateProperty, value); }
}
}
}
Thanks for taking a look, has me still currently stumped.
You are missing a call to InitializeComponent() in you UserControl's constructor.
I believe your namespace in the code you posted is incorrect.
By having new PropertyMetadata(null)); a property changed callback isn't being registered. Without that I believe binding won't work. What you want to do is bind to the property on your usercontrol and when the bound value changes, you want to set the value on the RadDateTimePicker contained in your control.
xaml:
<Grid Width="90">
<telerik:RadDateTimePicker x:Name="MyRadDateTimePicker" InputMode="DatePicker" />
<telerik:RadMaskedDateTimeInput x:Name="MyRadMaskedDateTimeInput"
IsClearButtonVisible="False"
FormatString="{}{0:M/d/yy}"
SelectionOnFocus="SelectAll" />
</Grid>
</UserControl>
code behind:
using System;
using System.Windows;
namespace SO
{
public partial class MyDatePicker
{
public MyDatePicker()
{
InitializeComponent();
}
public const string SelectedDatePropertyName = "SelectedDate";
public DateTime SelectedDate
{
get { return (DateTime)GetValue(SelectedDateProperty); }
set { SetValue(SelectedDateProperty, value); }
}
public static readonly DependencyProperty SelectedDateProperty = DependencyProperty.Register(
SelectedDatePropertyName,
typeof(DateTime),
typeof(MyDatePicker),
new PropertyMetadata(DateTime.Now, OnSelectedDatePropertyChanged));
private static void OnSelectedDatePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((MyDatePicker)d).MyRadDateTimePicker.SelectedDate = (DateTime) e.NewValue;
((MyDatePicker)d).MyRadMaskedDateTimeInput.Value = (DateTime)e.NewValue;
}
}
}
Related
I am very new to AvaloniaUI.
I am really struggling to change a text when I click a button.
Here is my code:
<Window xmlns="https://github.com/avaloniaui"
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"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ReadyForWar_Launcher.MainWindow"
Title="ReadyForWar_Launcher">
<StackPanel>
<TextBlock Name="TestBlock">Show my text here!</TextBlock>
<Button Command="{Binding RunTheThing}" CommandParameter="Hello World">Change the Text!</Button>
</StackPanel>
</Window>
Here is my MainWindow.xaml.cs:
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace ReadyForWar_Launcher
{
public class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
public void RunTheThing()
{
}
}
}
Inside RunTheThing I don't know how can I select the TextBlock with Name="TestBlock" and change the text to "Hello World".
Can you please help me out on this ?
There are two approaches, the recommended one and straightforward one.
Recommended: Use MVVM pattern. Create a view model with ButtonTextProperty and RunTheThing command, make the command to change the property, assign that model to the DataContext and bind your button text and command to view model properties. The MVVM approach is basically the same as in WPF, so you can use documentation and tutorials from there (that applies to most of the Avalonia, BTW). For example, here is a good one (not advertising, 4th link from google).
Straightforward (aka winforms-way): add x:Name="MyButton" to your button and use this.FindControl<Button>("MyButton") after calling AvaloniaXamlLoader.Load(this);. This will give you a Button reference that you can manipulate from code. Instead of using commands, you can just subscribe to the click handler directly from codebehind, add public void MyButton_OnClick(object sender, RoutedEventArgs args){} to your MainWindow class and add replace Command and CommandParameter with Click="MyButton_OnClick". That way button click will trigger your event handler.
Note, that the second approach doesn't scale well with the application size and suffers from code complexity when handling lists.
I am having a problem with the Visual Studio designer for a WPF project and the combination of binding to a type using a generic and specifying a nullable type as the generic type.
I have tried to construct a minimal example of the problem:
XAML:
<Window x:Class="TestWpfApp.MainWindow"
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:local="clr-namespace:TestWpfApp"
mc:Ignorable="d" d:DataContext="{d:DesignInstance local:TestViewModel}"
Title="MainWindow" Height="450" Width="800">
<Grid>
<TextBlock Text="{Binding TestText.Value}"/>
<!--<TextBlock Text="{Binding TestTextValue}"/>-->
</Grid>
</Window>
Code behind:
using System.Windows;
namespace TestWpfApp
{
public class TestGeneric<T>
{
public TestGeneric(T value)
{
Value = value;
}
public T Value { get; }
}
public class TestViewModel
{
public TestGeneric<double?> TestText { get; } = new TestGeneric<double?>(123.456);
public double? TestTextValue => TestText.Value;
}
public partial class MainWindow : Window
{
public MainWindow()
{
DataContext = new TestViewModel();
InitializeComponent();
}
}
}
The designer fails with this code with the following error message:
System.Runtime.Remoting.RemotingException
[16040] Designer process terminated unexpectedly!
The commented out line in the XAML code does not give the error in the designer window.
Both versions actually work when running the project. It is only the designer that fails.
Does anyone have any idea about what the problem could be?
The d:DataContext design time expression is a very practical trick, and IDE related, it has no impact on the runtime, only affect the design time. Applicable in Visual Studio 2010 and later.
The default constructor is required for a type to be instantiated in XAML.
The option IsDesignTimeCreatable=True tells the designer that it can create the specified class via default constructor. This way it is possible to provide sample data for the UI.
d:DataContext="{d:DesignInstance local:TestViewModel , IsDesignTimeCreatable=True }"
Yong Lu
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.
EDIT:
The problem was that my View Models were not public, so the bindings were not found. For some reason they need to be public in Silverlight, even though private view models work for WPF. More detail in my answer below.
I am trying to implement an MVVM WPF app in Silverlight, but I have never used Silverlight before. I am struggling to get the bound content to display. I am implementing it almost exactly how I did with WPF, except that the Main bit is a UserControl, not a Window, the app is hosted by a Web Site, and I had to remove the x:Type in DataTemplate DataType
My Website-to-MainPage is working properly, because I can display a text box or something in that page, however the Binding is just not displayed. Any suggestions?
My MainPage.xaml.cs:
public partial class MainPage : UserControl
{
private MainPageViewModel _viewModel;
public MainPage()
{
InitializeComponent();
_viewModel = new MainPageViewModel();
this.DataContext = _viewModel;
}
}
My MainPage.xaml:
<UserControl x:Class="TransformationServices.Silverlight.MainPage"
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"
mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"
xmlns:view="clr-namespace:TransformationServices.Silverlight.View"
xmlns:viewModel="clr-namespace:TransformationServices.Silverlight.ViewModel"
xmlns:local="clr-namespace:TransformationServices.Silverlight"
Background="#FF2D2D30">
<UserControl.Resources>
<local:ViewConverter x:Key="viewConverter"/>
<DataTemplate DataType="viewModel:InputSelectViewModel">
<TextBlock Text="Hello World!"/>
<!-- This textblock is just for testing. It doesn't work, and neither does the following line-->
<view:InputSelect/>
</DataTemplate>
</UserControl.Resources>
<ContentControl Content="{Binding CurrentView}" />
</UserControl>
My MainPageViewModel.cs
class MainPageViewModel : ViewModelBase, INotifyPropertyChanged
{
private ViewModelBase _currentView;
private List<ViewModelBase> _viewModels;
private int _viewIndex;
public ViewModelBase CurrentView
{
get { return _currentView; }
set
{
if (value != _currentView)
{
_currentView = value;
OnPropertyChanged("CurrentView");
}
}
}
public MainPageViewModel()
{
_viewModels = new List<ViewModelBase>();
// Add view models here
_viewModels.Add(new InputSelectViewModel());
_viewIndex = 0;
CurrentView = _viewModels[_viewIndex];
}
}
It would appear as though the problem is that my ViewModels were not public. I noticed in the Output the following type of message:
System.Windows.Data Error: Cannot get '<Whatever property of View Model>' value ...
This message was coming up for every property that I was binding to, including CurrentView. After making the View Models public, the bindings worked perfectly. It seems odd to me that Silverlight would need the classes to be public when they worked fine as private for WPF, but this is my first time working with Silverlight, so this intricacy tripped me up. Hopefully this answer can help someone in the future. Anyway, this is the main reason for why the bindings were not working, and thus the CurrentView was not being displayed.
Another reason that it was hard for me to debug this issue is that my page was accidentally caching everything, so some of my changes would not display. This link helped me with that:
http://www.codeproject.com/Articles/143414/Prevent-your-Silverlight-XAP-File-from-Caching-in
I am creating a custom control that when invoked in the XAML can be set to only allow certain types of inputs:
<lib:CustomControl RestrictTo="UnsignedIntegersOnly" ... ></CustomControl>
Where the UnsignedIntegersOnly is part of an Enum containing the set of allowed restrictions.
If the user inputs something that is not allowed, the control will throw a validation error and not allow him to continue to the next form/page/etc.
My vision for implementing this, was to, in the underlying TextBox that makes up this control, bind its text field to a validation rule which will be passed as an input the RestrictTo value that was specified in the CustomControl XAML declaration. Then in that ValidationRule class, handle the RestrictTo specific validation and return whether the validation was successful or not.
This is where I am not quite sure how to proceed. Is it even possible to pass arguments to the ValidationRule in such a seemingly dynamic manner? I am setting a property, RestrictTo, of my control and then passing that to its validation.
If it is possible, how would it be done? What sort of binding or resource linking should I use?
You might be interested in using a MaskedTextBox control, it will restrict what the user can input in the TextBox.
As there's no official control from Microsoft for WPF I would suggest the following from Xceed :
MaskedTextBox (it's free to use :-)
Here you have the syntax of the mask :
http://msdn.microsoft.com/en-us/library/system.windows.forms.maskedtextbox.mask.aspx
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
Title="MainWindow" Height="350" Width="525">
<Grid>
<xctk:MaskedTextBox Mask="0000"></xctk:MaskedTextBox>
</Grid>
</Window>
If you have Visual Studio 2012 you can easily get this package through NuGet :
(right-click on your project )
Note : on my answer to your previous question, I extensively used validation rules in the link I posted but I'd say that if there are some times where you can avoid it through the means of a well-crafted component/control, then it's wise to do so. As #Barn pointed out on your previous question, a generic validation rule might be a hard thing to do and somewhat questionable as you'll have to handle all the types in it, IMO it's a little counter-intuitive as validators and converters are generally specific against being generalist; you're likely to waste more time on it than it's worth and it will be probably less re-usable than you think it could be. (source : my experience)
Below code should get you started. It is a user control and not a custom control. I recomend you get your code working as a user control first and then convert it to a custom control. Bind Valid property to some property in your viewmodel that controls user workflow.
XAML:
<UserControl x:Class="WpfApplication.ValidatingControl"
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" >
<StackPanel Orientation="Horizontal">
<TextBox Name="_textBox" TextChanged="OnTextChanged" Background="LightGray" Width="200"/>
<TextBlock Name="_messageText" Foreground="Red" />
</StackPanel>
</UserControl>
Code behind:
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication
{
public partial class ValidatingControl : UserControl
{
public ValidatingControl()
{
InitializeComponent();
}
public enum Restrictions
{
UnsignedIntegersOnly,
SmallIntegersOnly
}
public static readonly DependencyProperty RestrictToProperty =
DependencyProperty.Register("RestrictTo", typeof(Restrictions), typeof(ValidatingControl), new PropertyMetadata(Restrictions.UnsignedIntegersOnly));
public Restrictions RestrictTo
{
get { return (Restrictions)GetValue(RestrictToProperty); }
set { SetValue(RestrictToProperty, value); }
}
public bool Valid
{
get { return (bool)GetValue(ValidProperty); }
set { SetValue(ValidProperty, value); }
}
public static readonly DependencyProperty ValidProperty =
DependencyProperty.Register("Valid", typeof(bool), typeof(ValidatingControl), new UIPropertyMetadata(false));
private void OnTextChanged(object sender, TextChangedEventArgs e)
{
ValidateText(RestrictTo, _textBox.Text);
}
private void ValidateText(Restrictions restrictTo, string text)
{
// validate text, update _messageText, update Valid
}
}
}