Failed to create a 'Path' from the text '(P5:FButton.TextBlockText)' - c#

I created a attached property for a Button to set a TextBlock Text property in a canvas in Button ControlTemplate but I get this exception in design time in Visual Studio 2013. In Blend show an errorbox in place of button, but at Run time it`s working fine.
This is the attached property Class:
public class FButton
{
public static readonly DependencyProperty TextBlockTextProperty =
DependencyProperty.RegisterAttached("TextBlockText",
typeof(string),
typeof(FButton),
new FrameworkPropertyMetadata(null));
public static string GetTextBlockText(DependencyObject d)
{
return (string)d.GetValue(TextBlockTextProperty);
}
public static void SetTextBlockText(DependencyObject d, string value)
{
d.SetValue(TextBlockTextProperty, value);
}
}
This is the TextBlock in ControlTemplate:
<TextBlock x:Name="F1" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(custom:FButton.TextBlockText)}" Foreground="Black" FontSize="14" IsHyphenationEnabled="True" LineStackingStrategy="BlockLineHeight" LineHeight="14" TextAlignment="Left" TextWrapping="Wrap" Opacity="0.895"/>
And this is the Button:
<Button x:Name="btnF1" Template="{StaticResource TmpBtnF}" custom:FButton.TextBlockText="F1" Content="Button" Grid.Column="2" Margin="0,7,-1,618.669" Grid.Row="1"/>
And if is not a problem, can you give me some idea, how I can push this button on F1 keypress?

Related

How can I set the focus on DecimalUpDown via Button Command base on validation

XAML View Code
<xctk:DecimalUpDown Value="{Binding InitialDepositAmount, Mode=TwoWay}" Minimum="{Binding MinimumAllowedAmount}" Maximum="{Binding MaximumAllowedAmount}" HorizontalAlignment="Right" Grid.Column="1" VerticalAlignment="Center" Width="120" Height="21" Margin="5 0 0 0" />
<xctk:DecimalUpDown Value="{Binding CardPaymentAmount, Mode=TwoWay}" Minimum="{Binding MinimumAllowedAmount}" Maximum="{Binding MaximumAllowedAmount}" HorizontalAlignment="Right" Grid.Column="1" VerticalAlignment="Center" Width="120" Height="21" Margin="5 0 0 0" />
<Button Command="{Binding ProccessButtonCommand}" BorderBrush="#a7a7a7" BorderThickness="1" Grid.Column="0" HorizontalContentAlignment="Left" Width="162" Height="42" Margin="0 10 0 0">
ViewModel Code
private void ExecuteProccessButtonCommand(object obj)
{
if (InitialDepositAmount == 100)
//Focus Initial Depostit DecimalUpDown
if (CardPaymentAmount== 100)
//Focus Card Payment DecimalUpDown
}
private DelegateCommand<object> _proccessButtonCommand;
public DelegateCommand<object> ProccessButtonCommand =>
_proccessButtonCommand ? ? (_proccessButtonCommand = new DelegateCommand<object> (ExecuteProccessButtonCommand));
The logic goes like this. I would only like approach that uses only MVVM.
You could created an attached behavior for DecimalUpDown that has a condition and target button. You need to use the Microsoft.Xaml.Behaviors.Wpf NuGet package for this.
public class FocusConditionBehavior : Behavior<DecimalUpDown>
{
public static readonly DependencyProperty TargetProperty = DependencyProperty.Register(
nameof(Target), typeof(ButtonBase), typeof(FocusConditionBehavior), new PropertyMetadata(null, OnTargetChanged));
public static readonly DependencyProperty ConditionProperty = DependencyProperty.Register(
nameof(Condition), typeof(bool), typeof(FocusConditionBehavior), new PropertyMetadata(false));
public ButtonBase Target
{
get => (ButtonBase)GetValue(TargetProperty);
set => SetValue(TargetProperty, value);
}
public bool Condition
{
get => (bool)GetValue(ConditionProperty);
set => SetValue(ConditionProperty, value);
}
private static void OnTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((FocusConditionBehavior)d).OnTargetChanged((ButtonBase)e.OldValue, (ButtonBase)e.NewValue);
}
private void OnTargetChanged(ButtonBase oldButtonBase, ButtonBase newButtonBase)
{
if (oldButtonBase != null)
oldButtonBase.Click -= OnClick;
if (newButtonBase != null)
newButtonBase.Click += OnClick;
}
private void OnClick(object sender, RoutedEventArgs e)
{
if (Condition)
Keyboard.Focus(AssociatedObject);
}
}
Create bool properties in your view model that represent the conditions. Make sure that you update these properties using INotifyPropertyChanged when the corresponding data properties change to notify the user interface of changes.
public bool IsInitialDepositAmountMatching
{
get
{
// You are free to add any conditions here
return InitialDepositAmount == 100;
}
}
Then assign a name to the button that should trigger evaluating the conditions and focusing, e.g. TestButton and attach the beahvior with appropriate bindings to the DecimalUpDowns.
<xctk:DecimalUpDown>
<b:Interaction.Behaviors>
<local:FocusConditionBehavior Condition="{Binding IsInitialDepositAmountMatching}"
Target="{Binding ElementName=TestButton}"/>
</b:Interaction.Behaviors>
</xctk:DecimalUpDown>
<xctk:DecimalUpDown>
<b:Interaction.Behaviors>
<local:FocusConditionBehavior Condition="{Binding IsCardPaymentAmountMatching}"
Target="{Binding ElementName=TestButton}"/>
</b:Interaction.Behaviors>
</xctk:DecimalUpDown>
This way, focusing is handled MVVM-compliant in the view and is packed as reusable component as a bonus.

Force or otherwise initiate TwoWay TestBox data binding

I've got a WPF TextBox with TwoWay binding to a ViewModel property. I also have a ToolBar with a Button. When the Button is clicked, it executes a command on the same ViewModel that will do something with the property the TextBox is bound to.
Unfortunately it looks like the Binding only sends the text back to the binding target when the TextBox loses focus. The Button on the Toolbar however does not take focus when clicked. The upshot being that when the Command executes it does not have the text from the textbox, but rather the last value that was bound.
The Xaml looks like so:
<DockPanel LastChildFill="True" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" >
<ToolBarTray Background="White" DockPanel.Dock="Top">
<ToolBar Band="1" BandIndex="1">
<Button Command="{Binding QueryCommand}">
<Image Source="images\media_play_green.png" />
</Button>
</ToolBar>
</ToolBarTray>
<DataGrid VerticalAlignment="Top" DockPanel.Dock="Top" Height="450" AutoGenerateColumns="True"
ItemsSource="{Binding}" DataContext="{Binding Results}" DataContextChanged="DataGrid_DataContextChanged"/>
<TextBox DockPanel.Dock="Bottom" Text="{Binding Sql, Mode=TwoWay}"
AcceptsReturn="True" AcceptsTab="True" AutoWordSelection="True" TextWrapping="WrapWithOverflow"/>
</DockPanel>
How do I get the TextBox's Text binding to update the ViewModel when the ToolBar button is pressed. There is nothing fancy going on in the ViewModel which looks like so:
public class MainViewModel : ViewModelBase
{
private readonly IMusicDatabase _database;
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel(IMusicDatabase database)
{
_database = database;
QueryCommand = new RelayCommand(Query);
}
public RelayCommand QueryCommand { get; private set; }
private async Task QueryAndSetResults()
{
Results = await _database.Query(Sql);
}
private void Query()
{
QueryAndSetResults();
}
private IEnumerable<object> _results;
public IEnumerable<object> Results
{
get
{
return _results;
}
private set
{
Set<IEnumerable<object>>("Results", ref _results, value);
}
}
private string _sql = "SELECT * FROM this WHERE JoinedComposers = 'Traditional'";
public string Sql
{
get { return _sql; }
set
{
Set<string>("Sql", ref _sql, value);
}
}
}
You can use the UpdateSourceTrigger property of the binding, setting it to PropertyChanged makes the TextBox refresh the binding every time the text changes, not just when losing focus:
<TextBox DockPanel.Dock="Bottom"
Text="{Binding Sql, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
AcceptsReturn="True"
AcceptsTab="True"
AutoWordSelection="True"
TextWrapping="WrapWithOverflow"/>
More info at MSDN.

Binding properties of User Control in Windows Phone Application

In a LongListSelector, I have multiple items shown, according to the following DataTemplate :
<TextBlock Text="{Binding Subject}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="Last modified :" Margin="15, 0, 5, 0" Foreground="LightGray" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Text="{Binding LastModified}" Foreground="#989696" Style="{StaticResource PhoneTextNormalStyle}"/>
</StackPanel>
At this point, everything works fine, the MVVM and bindings are OK.
I wanted to move this XAML into an UserControl and bind those properties from it. And, I have thought to proceed in this way :
<UserControl x:Class="..."
xmlns=" ... "
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="100" d:DesignWidth="480">
<StackPanel x:Name="LayoutRoot" Background="Transparent">
<TextBlock x:Name="TitleTextBlock" Style="{StaticResource PhoneTextExtraLargeStyle}" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="Last modified :" Margin="15, 0, 5, 0" Foreground="LightGray" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="LastModifiedDateTextBlock" Foreground="#989696" Style="{StaticResource PhoneTextNormalStyle}"/>
</StackPanel>
</StackPanel>
</UserControl>
And this is the C# class :
public partial class LongListSelectorItemControl
{
private DateTime _lastModifiedDate;
public string Title
{
get
{
return TitleTextBlock.Text;
}
set
{
TitleTextBlock.Text = value;
}
}
public DateTime LastModifiedDate
{
get
{
return _lastModifiedDate;
}
set
{
LastModifiedDateTextBlock.Text = value.ToString(CultureInfo.InvariantCulture);
_lastModifiedDate = value;
}
}
public LongListSelectorItemControl()
{
InitializeComponent();
_lastModifiedDate = new DateTime();
}
}
I have thought to use the user control in XAML in this way :
<userControls:LongListSelectorItemControl Title="{Binding Subject}" LastModifiedDate="{Binding LastModified}"/>
But something went wrong and I can't figure out what. I guess it has to do something with an incorrect binding... because in my application, a page is loaded with this XAML I presented in this issue and the app doesn't crash. Then the user has to navigate to another page, where some data is added and the ViewModel will have some data to show, so when it returns to the main page, this time, it simply crashes... (gets me to Application_UnhandledException method in App.xaml.cs to break the debugger.
Additional research
I've managed to track down the exception and it seems...
MS.Internal.WrappedException: Object of type 'System.Windows.Data.Binding' cannot be converted to type 'System.String'. ---> System.ArgumentException: Object of type 'System.Windows.Data.Binding' cannot be converted to type 'System.String'
I am still confused on how to fix this...
Any suggestions are welcome to aid me into figuring out what's wrong. Thanks!
To be able to bind to a property, it need to be a dependency property. Here is how the title property need to be modified:
public partial class LongListSelectorItemControl
{
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(LongListSelectorItemControl), new PropertyMetadata(default(string), TitlePropertyChanged));
private static void TitlePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
LongListSelectorItemControl myControl=d as LongListSelectorItemControl;
myControl.TitleTextBlock.Text = e.NewValue as string;
}
public string Title
{
get { return (string) GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
....
}
You will need to do the same thing with the LastModifiedDate property.

OnPropertyChanged method is not firing

In WP8 app, i have few controls where i bind the foreground color which i am changing in the codebehind. But OnPropertyChanged is not firing when the user event happened.
I have defined this binding "ControlForeground" in my textblock and radiobutton data template controls in it. I am trying to change the Foreground color whenever user presses the button. But my new color assignment is not updating the UI. Anything i am missing here?
In XAML,
<TextBlock x:Name="lblTileColor" TextWrapping="Wrap" Text="Selected color:" Foreground="{Binding ControlForeground, Mode=TwoWay}"/>
<TextBlock x:Name="lblTileColor2" TextWrapping="Wrap" Text="App bg:" Foreground="{Binding ControlForeground, Mode=TwoWay}"/>
<RadioButton x:Name="accentColor" IsChecked="true" BorderBrush="White" Foreground="{Binding ControlForeground, Mode=TwoWay}">
<RadioButton.ContentTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Rectangle Width="25" Height="25" Fill="{StaticResource PhoneAccentBrush}"/>
<TextBlock Width="10"/>
<TextBlock x:Name="lblDefaultAccent" Text="Default accent color" Foreground="{Binding ControlForeground, Mode=TwoWay}"/>
</StackPanel>
</DataTemplate>
</RadioButton.ContentTemplate>
</RadioButton>
<Button x:name="UpdateColor" click="update_btn"/>
In C#,
public class ColorClass : INotifyPropertyChanged
{
private SolidColorBrush _ControlForeground;
public SolidColorBrush ControlForeground
{
get
{
return _ControlForeground;
}
set
{
_ControlForeground = value;
OnPropertyChanged("ControlForeground");
}
}
public ColorClass() { }
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
public class ColorPage:PhoneApplicationPage{
public ObservableCollection<ColorClass> TestCollection { get; private set; }
public void update_btn(object sender, EventArgs e){
TestCollection.Add(new ColorClass()
{
ControlForeground = new SolidColorBrush(Colors.Red)
});
}
}
For your 2nd problem (not being able to bind controls inside your data template), this is because these controls will use the data context of the their parent template not the data context of the page.
To fix this, you'll have to tell these controls the element name with the data context and give it full path of your property.
<TextBlock
x:Name="lblDefaultAccent"
Text="Default accent color"
Foreground="{Binding DataContext.ControlForeground,
ElementName=LayoutRoot, Mode=TwoWay}"/>
As you can see above you have to specify the element name. In case you bound this using this.DataContext = colorClass then the element name will be the name of the outer grid in your xaml, defaulted as LayoutRoot
You can only bind an ObservableCollection to controls which expect it, like a ListBox or LongListSelector. Additionally, adding a Brush to the TestCollection doesn't fire the non-functional notification since it doesn't call the setter of that property, just modifies the existing object.
Make TestCollection a type ColorClass and change the .Add stuff to just change the ColorClass.ControlForeground property and this should "just work."

Silverlight controls defined in xaml are null at runtime

I have made a user control called Section which has 2 custom DependencyProperty: Title and Elements (kinda like content). I have used Section on several pages it displays just fine on every page.
The following xaml code is a part of my AccountView class
<Controls:Section Title="Epic Movies" Grid.Column="1" Grid.Row="1" x:Name="DescriptionSection" Visibility="Collapsed">
<Controls:Section.Elements>
<StackPanel>
<TextBlock Style="{StaticResource FrameLabel}" Text="Description:" Grid.Column="1"/>
<TextBlock x:Name="DescriptionField" Style="{StaticResource FrameText}" Text="some text..." Grid.Column="1" Grid.Row="1"/>
<TextBlock Text="Products:" Style="{StaticResource FrameLabel}"/>
<ScrollViewer Margin="12,0" VerticalScrollBarVisibility="Auto" MaxHeight="180">
<StackPanel x:Name="ProductList"/>
</ScrollViewer>
<TextBlock Style="{StaticResource FrameLabel}" Text="Category"/>
<TextBlock x:Name="CategoryField" Style="{StaticResource FrameText}" Text="some category"/>
<TextBlock Style="{StaticResource FrameLabel}" Text="Views:"/>
<TextBlock x:Name="ViewsField" Style="{StaticResource FrameText}" Text="12322 Views"/>
<TextBlock Style="{StaticResource FrameLabel}" Text="Price:"/>
<TextBlock x:Name="PriceField" Style="{StaticResource FrameText}" Text="455$"/>
<Button Content="Go to Module" Grid.Column="1" FontSize="15" Grid.Row="1" VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="20,15"/>
</StackPanel>
</Controls:Section.Elements>
</Controls:Section>
When i try set the text of my TextBlocks in c# code all the TextBlock are null
private void ShowModuleInformation(Module m)
{
DescriptionSection.Title = m.Name;
//DescriptionField is null even though clearly defined in xaml
DescriptionField.Text = m.Description;
PriceField.Text = m.Price + "";
ViewsField.Text = m.views+"";
CategoryField.Text = m.Category.Name;
foreach (Product p in m.Products)
{
TextBlock t = new TextBlock() { Text = p.Name };
ProductList.Children.Add(t);
}
DescriptionSection.Visibility = Visibility.Visible;
}
My Section c# class looks as follow:
public partial class Section : UserControl
{
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
"Title", typeof(string), typeof(Section), new PropertyMetadata(new PropertyChangedCallback(TitleChanged)));
public static readonly DependencyProperty ElementsProperty = DependencyProperty.Register(
"Elements", typeof(UIElement), typeof(Section), new PropertyMetadata(new PropertyChangedCallback(ElementsChanged)));
public Section()
{
InitializeComponent();
}
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
public UIElement Elements
{
get { return (UIElement)GetValue(ElementsProperty); }
set { SetValue(ElementsProperty, value); }
}
private static void TitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var sec = (Section)d;
if (sec != null)
{
sec.TitleField.Text = (string)e.NewValue;
}
}
private static void ElementsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Section sec = (Section)d;
if (sec != null)
{
sec.ElementPanel.Content = (UIElement)e.NewValue;
}
}
I have solved this with a little help from this thread. All i needed to do was to make Section derive ContentControl instead of User Control

Categories