I have a simple UserControl in a XAML Windows RT app. The DependencyProperty appears to be set just fine, and breakpoints in the code show the target property of 'TwitterMessage' gets the correct object at runtime, after the 'IsLoaded' event. The problem is, the binding values inside the UserControl's child controls are empty when the XAML is rendered. It's like its ignoring the values of the TwitterMessage property. Any ideas? Intellisense seems to think I'm doing it right as it autocompletes the bindings in the markup.
The Usercontrol is given a simple invocation like so:
<local:TwitterMessageUserControl TwitterMessage="{Binding Message}" Grid.Column="2" />
UserControl Markup is as follows:
<UserControl
x:Class="TwitterMessageUserControl"
...
x:Name="root">
<Border Height="85" Width="400" BorderBrush="{ThemeResource ApplicationSecondaryForegroundThemeBrush}" BorderThickness="1" >
<StackPanel Background="{ThemeResource AppBarItemForegroundThemeBrush}" Orientation="Horizontal">
<Image HorizontalAlignment="Left" Height="73" x:Name="Avatar" VerticalAlignment="Top" Width="73" Margin="10,5,0,0" Source="{Binding ElementName=root, Path=TwitterMessage.Tweet.AuthorAvatarUrl}"/>
<StackPanel Margin="15,0,0,0">
<TextBlock HorizontalAlignment="Left" x:Name="TweetText" TextWrapping="Wrap" Text="{Binding ElementName=root, Path=TwitterMessage.Tweet.Message, Mode=OneWay}" VerticalAlignment="Top" Foreground="Black" Width="300" Margin="0,10,0,0" FontSize="12"/>
<TextBlock TextWrapping="Wrap" Text="— #someone via Twitter" x:Name="TweetFromText" Foreground="Black" Margin="0,5,0,0"/>
</StackPanel>
</StackPanel>
</Border>
And codebehind is as follows:
public sealed partial class TwitterMessageUserControl : UserControl
{
public static readonly DependencyProperty TwitterMessageProperty =
DependencyProperty.Register("TwitterMessage", typeof(TweetMessage), typeof(TwitterMessageUserControl), new PropertyMetadata(null));
public TweetMessage TwitterMessage
{
get { return (TweetMessage)GetValue(TwitterMessageProperty); }
set { SetValue(TwitterMessageProperty, value); }
}
public TwitterMessageUserControl()
{
this.InitializeComponent();
this.Loaded += TwitterMessageUserControl_Loaded;
}
void TwitterMessageUserControl_Loaded(object sender, RoutedEventArgs e)
{
DataContext = this;
}
}
I recreated the app quickly. When running the app I noticed this error in the debug output:
Error: BindingExpression path error: 'Message' property not found on
'App4.TwitterMessageUserControl'. BindingExpression: Path='Message'
DataItem='App4.TwitterMessageUserControl'; target element is
'App4.TwitterMessageUserControl' (Name='root'); target property is
'TwitterMessage' (type 'TweetMessage')
The problem is that when you do DataContext = this; in the TwitterMessageUserControl_Loaded it will look for a Message property on itself instead of the DataContext set in your view. Comment out this line and it should work fine:
Additionally if you want to simplify the bindings further in the UserControl XAML you can bind to the root in the Border, and then just bind without specifying the ElementName for every binding inside that, like this:
<Border DataContext="{Binding ElementName=root}" Height="85" Width="400" BorderBrush="{ThemeResource ApplicationSecondaryForegroundThemeBrush}" BorderThickness="1" >
<StackPanel Background="{ThemeResource AppBarItemForegroundThemeBrush}" Orientation="Horizontal">
<Image HorizontalAlignment="Left" Height="73" x:Name="Avatar" VerticalAlignment="Top" Width="73" Margin="10,5,0,0" Source="{Binding TwitterMessage.Tweet.AuthorAvatarUrl}"/>
<StackPanel Margin="15,0,0,0">
<TextBlock HorizontalAlignment="Left" x:Name="TweetText" TextWrapping="Wrap" Text="{Binding TwitterMessage.Tweet.Message}" VerticalAlignment="Top" Foreground="Black" Width="300" Margin="0,10,0,0" FontSize="12"/>
<TextBlock TextWrapping="Wrap" Text="— #someone via Twitter" x:Name="TweetFromText" Foreground="Black" Margin="0,5,0,0"/>
</StackPanel>
</StackPanel>
</Border>
Related
How do I bind an element in another usercontrol to a command target?
This is main xaml
<Grid>
<StackPanel>
<Button Height="200" x:Name="PageUpButton" FontFamily="Marlett" FontSize="40" Content="5" Command="{x:Static ScrollBar.PageUpCommand}" CommandTarget="{Binding ElementName=scrollViewerActive}"/>
<local:posMenuChild x:Name="PosMenuChild"/>
<Button Height="200" x:Name="PageDownButton" FontFamily="Marlett" FontSize="40" Content="6" Command="{x:Static ScrollBar.PageDownCommand}" CommandTarget="{Binding ElementName=ScrollViewerActive }"/>
</StackPanel>
</Grid>
What should I specify as CommandTarget?
How do I scroll the element in the following UserControl with the Button in the top Window?
This is usercontrol
<Grid Height="200">
<WrapPanel Orientation="Vertical" Height="200">
<ScrollViewer VerticalScrollBarVisibility="Hidden" Name="ScrollViewerActive" CanContentScroll="True" >
<StackPanel>
<TextBlock Text="Test1" FontSize="35"/>
<TextBlock Text="Test2" FontSize="35"/>
<TextBlock Text="Test3" FontSize="35"/>
<TextBlock Text="Test4" FontSize="35"/>
<TextBlock Text="Test5" FontSize="35"/>
<TextBlock Text="Test6" FontSize="35"/>
</StackPanel>
</ScrollViewer>
</WrapPanel>
</Grid>
Modify your usercontrol's code-behind with following:
First, add a DependencyProperty to bind to of a ScrollViewer type
public static readonly DependencyProperty ScrollTargetProperty = DependencyProperty.RegisterAttached(
"ScrollTarget", typeof(ScrollViewer), typeof(UserControl1), new PropertyMetadata(null));
public static void SetScrollTarget(DependencyObject element, ScrollViewer value)
{
element.SetValue(ScrollTargetProperty, value);
}
public static ScrollViewer GetScrollTarget(DependencyObject element)
{
return (ScrollViewer)element.GetValue(ScrollTargetProperty);
}
Don't forget to change UserControl1 to your usercontrol's class name.
Then, set this property to ScrollViewerActive (i did it inside the control's constructor)
SetScrollTarget(this, ScrollViewerActive);
And now you can bind to it like this
<Button Command="{x:Static ScrollBar.PageUpCommand}" CommandTarget="{Binding Path=ScrollTarget, ElementName=PosMenuChild, Mode=OneWay}"/>
I want to create a pivot, with a DataBinding to a List of PivotItems.
Each of these items should be surrounded by a ScrollViewer.
Unfortunately it doesn't work the way I was thinking....
My code:
MainPage:
<Page
x:Class="PivotSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:PivotSample"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Pivot Title="Pivot" SelectedItem="{Binding CurrentPivotItem, Mode=TwoWay}" ItemsSource="{Binding PivotItems}">
<Pivot.ItemTemplate>
<DataTemplate>
<ScrollViewer>
<UserControl Content="{Binding Content}"/>
</ScrollViewer>
</DataTemplate>
</Pivot.ItemTemplate>
</Pivot>
</Grid>
UserControl (the second UserControl is the same):
<UserControl
x:Class="PivotSample.MyUserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:PivotSample"
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">
<StackPanel Background="Yellow">
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
</StackPanel>
ViewModel:
public class ViewModelMainPage : ViewModelBase
{
private IList<PivotItem> _pivotItems;
private PivotItem _currentPivotItem;
public IList<PivotItem> PivotItems
{
get { return _pivotItems; }
set { _pivotItems = value; }
}
public PivotItem CurrentPivotItem
{
get { return _currentPivotItem; }
set
{
OnPropertyChanged(nameof(CurrentPivotItem));
_currentPivotItem = value;
}
}
}
When I start the project comes following message: "The program '[2940] name.exe' has exited with code -1 (0xffffffff).
But when I replace the ScrollViewer with a Grid or StackPanel it will works but then I won't see all of my PivotItem.
Any ideas?
(Putting a new answer, as the question has changed it's context.)
Looks like the Pivot Control screws up, if you use a list of PivotItems at it'
s ItemsSource.
Anyway: That's not the way DataBindings are intended.
As the name suggests, you bind to Data, not to controls or UI Elements. PivotItems are UI Controls (although they are more of a logical than a visual representation) and should not be part of your ViewModel.
Just change the type in your ViewModel to some actual data (a List of String, Object, or whatever classes you create) and it works fine
Alternatively, if you want to place a fixed content inside a Pivot Control, you don't need to bind it at all and you can just place the PivotItems directly in Xaml:
<Pivot>
<PivotItem Header="First Item">
<!-- your content display here -->
</PivotItem>
<PivotItem Header="Secont Item">
<!-- your content display here -->
</PivotItem>
</Pivot>
(Outdated, as question was updated)
You can only set ItemControls as ItemsPanelTemplate and the Scrollviewer ist not an ItemsControl, but a ContentControl (it only wraps a single child and does not display multiple items).
Also, ItemsPanelTemplate is the wrong target for what you are trying to achieve: If you want to change the content of the PivotItems inside the Pivot, just set the regular ItemTemplate.
<Pivot>
<Pivot.ItemTemplate>
<DataTemplate>
<ScrollViewer>
<!-- your content display here -->
</ScrollViewer>
</DataTemplate>
</Pivot.ItemTemplate>
</Pivot>
I want to make a list of ToggleButtons. Each of them is binded to a popup.
I had a problem with that, so I tried to put everything inside a StackPanel.
But, now, when the app is running, it shows an empty space (for the Popup) right after the ToggleButton. What can I do to solve that?
I've just added two images:
The first one is when the page is being uploaded.
The second one is when I scroll down the page.
<ListView x:Name="ListOfRecipes" HorizontalAlignment="Center" VerticalAlignment="Top" ItemsSource="{Binding}" Grid.Row="1" Margin="25,0.333,25,35" ScrollViewer.VerticalScrollMode="Enabled" Grid.RowSpan="5" >
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<ToggleButton x:Name="RecipeButton" Grid.Row="1" BorderBrush="#FF65C365" VerticalAlignment="Center" HorizontalAlignment="Center" Click="Button_Click" Height="150" Width="328" >
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" Height="128" Width="328">
<Image Source="{Binding Path=ImageUri}" Height="128" Width="128" Margin="0,6,0,-5.667" />
<StackPanel Orientation="Vertical" HorizontalAlignment="Left" VerticalAlignment="Top" Height="128" Width="192">
<TextBlock Height="25" Width="190" Foreground="#FF6FDC13" Text="{Binding Name}" VerticalAlignment="Top" />
<Image Name="YesOrNoImage" Source="{Binding Path=YesOrNoImage}" Width="102" Height="102" HorizontalAlignment="Center" VerticalAlignment="Bottom"/>
</StackPanel>
</StackPanel>
</ToggleButton>
<Popup IsOpen="{Binding IsChecked, ElementName=RecipeButton, Mode=TwoWay}" Height="514" Width="328" VerticalAlignment="Center" Name="PopupOne" Grid.Row="1" Grid.RowSpan="4" IsLightDismissEnabled="True" IsHoldingEnabled="False" ScrollViewer.VerticalScrollMode="Enabled" >
<Border BorderBrush="#FF65C365" BorderThickness="1" Background="White" Height="514" Width="328">
<StackPanel Orientation="Vertical" ScrollViewer.VerticalScrollMode="Enabled">
<Image Source="{Binding Path=ImageUri}" Height="328" Width="328" />
<TextBlock Foreground="#FF6FDC13" Text="{Binding Name}" HorizontalAlignment="Left" FontSize="28" />
<ScrollViewer VerticalScrollMode="Enabled" >
<TextBlock Foreground="Black" Text="{Binding RecipeText}" HorizontalAlignment="Left" FontSize="18" />
</ScrollViewer>
</StackPanel>
</Border>
</Popup>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
It seems that the issue is caused by the <PopUp Height=514/>
To test it, set the height to 0 to see if it fixes the gap. If so, you can bind the visibility to PopUp.IsOpen using a Visibility converter (I think Blue MVVM has one). Since I'm not very educated on Converters at the moment, I came up with a workaround.
public RecipeButton : INotifyPropertyChanged {
// Need to implement INotifyPropertyChanged logic on IsCheckedVisiblity for UI to be notified of visibility changes
public Visibility IsCheckedVisibility { get; set; }
private bool _IsChecked;
public bool IsChecked {
get { return _IsChecked };
set { _IsChecked = value;
this.IsCheckedVisibility = value == true ? Visiblity.Collapsed : Visiblity.Visible;
}
}
<PopUp Visibility = "{Binding IsCheckedVisibility}"/>
Let me know if that doesn't work and I'll try something else.
Plain and simple: I need to bind some properties of the ContextMenu items to a property of their parent in the DataTemplate.
I can't find a way to access it because ElementName doesn't work and RelativeSource allows me to use just Self or TemplatedParent.
Here's my code:
<telerikPrimitives:RadDataBoundListBox Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="3"
ItemsSource="{Binding Transfers.Keys, Source={StaticResource TransfersManager}, Mode=OneWay}">
<telerikPrimitives:RadDataBoundListBox.ItemTemplate>
<DataTemplate>
<toolkit:TransferControl x:Name="TransferControl"
Header="{Binding Converter={StaticResource TransferMonitorToDocumentTitleConverter}}"
IsContextMenuEnabled="False"
Icon="{Binding Converter={StaticResource TransferMonitorToDocumentIconUriConverter}}"
AutoHide="False"
Monitor="{Binding}"
Language="it-IT"
StatusTextBrush="Black"
Foreground="Black">
<toolkit:TransferControl.HeaderTemplate>
<DataTemplate>
<StackPanel>
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Header="item1"
IsEnabled="{Binding Monitor Property in the TransferControl object}"
/>
<toolkit:MenuItem Header="item2"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<Rectangle Fill="Transparent" Height="30"/>
<ContentControl Content="{Binding}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Foreground="Black" />
</StackPanel>
</DataTemplate>
</toolkit:TransferControl.HeaderTemplate>
</toolkit:TransferControl>
</DataTemplate>
</telerikPrimitives:RadDataBoundListBox.ItemTemplate>
What I'm trying to bind is:
<toolkit:MenuItem Header="item1"
IsEnabled="{Binding Monitor Property in the TransferControl object}"
/>
and I'd like to bind it to the Monitor property of the <toolkit:TransferControl x:Name="TransferControl" ... /> object.
I was able to solve this my simply creating a new UserControl that holds the content of your ListBox. I used the LongListSelector. Here is a solution that works.
First the XAML for the page:
<phone:LongListSelector Margin="0,0,-12,0" ItemsSource="{Binding Items}">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<local:WindowsPhoneControl/>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
Then the UserControl. This was nothing special, just a wrapper.
<UserControl x:Class="PivotApp1.WindowsPhoneControl"
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:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="480" d:DesignWidth="480">
<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">
<phone:LongListSelector x:Name="TransferControl" Margin="0,0,-12,0"
ItemsSource="{Binding Items}"
toolkit:TiltEffect.IsTiltEnabled="True">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<Grid>
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Header="item1"
IsEnabled="{Binding DataContext.Monitor, ElementName=TransferControl}"/>
<toolkit:MenuItem Header="item2"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<StackPanel Margin="0,0,0,17">
<TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</Grid>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</Grid>
</UserControl>
With this solution the Monitor property was hit when rendering the list. It will not be hit when opening the menu. Of course if you fire the propertyChanged for monitor, it will get the value again.
The property you want to bind to seems to be bound to the DataContext itself. Why not just bind to it (the DataContext) in the HeaderTemplate? All you need to do is bind the Header property to the DataContext, instead of converting it to something else, and then use the Converter inside the HeaderTemplate. Something like this:
<telerikPrimitives:RadDataBoundListBox.ItemTemplate>
<DataTemplate>
<toolkit:TransferControl x:Name="TransferControl"
Header="{Binding}"
IsContextMenuEnabled="False"
Icon="{Binding Converter={StaticResource TransferMonitorToDocumentIconUriConverter}}"
AutoHide="False"
Monitor="{Binding}"
Language="it-IT"
StatusTextBrush="Black"
Foreground="Black">
<toolkit:TransferControl.HeaderTemplate>
<DataTemplate>
<StackPanel>
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Header="item1"
IsEnabled="{Binding}"
/>
<toolkit:MenuItem Header="item2"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<Rectangle Fill="Transparent" Height="30"/>
<ContentControl Content="{Binding Converter={StaticResource TransferMonitorToDocumentTitleConverter}}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Foreground="Black" />
</StackPanel>
</DataTemplate>
</toolkit:TransferControl.HeaderTemplate>
</toolkit:TransferControl>
</DataTemplate>
</telerikPrimitives:RadDataBoundListBox.ItemTemplate>
On a side note, I think you may be doing too much binding. Bindings and converters can lead to bad performance and sometimes it's just faster and easier to do things without bindings.
Btw, may I ask what does the TransferMonitorToDocumentTitleConverter do?
Update
It seems there is a bug in the toolkit. The Header property's getter casts the object to string and so, even though the property is of type object, you can only set it to a string - otherwise an exception is thrown in the getter, which is used internally.
Here's a possible workaround:
Extend the TransferControl like this:
public class TransferControlFixed : TransferControl {
public static readonly DependencyProperty HeaderFixedProperty = DependencyProperty.Register("HeaderFixed", typeof(object), typeof(TransferControlFixed), new PropertyMetadata(null));
public object HeaderFixed {
get {
return GetValue(HeaderFixedProperty);
}
set {
SetValue(HeaderFixedProperty, value);
}
}
public override void OnApplyTemplate() {
base.OnApplyTemplate();
var control = (ContentControl)this.GetTemplateChild("Header");
control.SetBinding(ContentControl.ContentProperty, new Binding() {
Path = new PropertyPath("HeaderFixed"),
Source = this
});
}
}
Use TransferControlFixed instead of TransferControl and bind the HeaderFixed instead of the Header property.
It seems like a reasonably simple workaround.
I have a ViewModel and i am setting an instance of it to DataContext.In xaml i have binded the Listbox itemsource to an observable collection in ViewModel.But when i run the program nothing appears in listbox.What may be the Reason.
My ViewModel class:
public class ViewModel
{
public ObservableCollection<Data> _collectionData = new ObservableCollection<Data>();
-----
-----
}
Xaml:
ListBox Name="myListBox" Margin="8,113,8,8" ItemsSource="{Binding _collectionData}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<Border BorderThickness="3" BorderBrush="#A5FFFFFF" Width="80" Margin="0,20,0,20" Height="60">
<Image Source="{Binding ImageUrl, Mode=OneWay}" VerticalAlignment="Stretch" Margin="0,0,0,0" Width="80" Height="60" Stretch="Fill" />
</Border>
<TextBlock TextWrapping="Wrap" Text="{Binding Title}" FontSize="40" FontWeight="Normal" VerticalAlignment="Center" Margin="30,0,0,0" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Constructor of main page:
ViewModel vm = new ViewModel();
this.DataContext = vm;
But when i give myListBox.ItemsSource = vm._collectionSplashData; it works .what may be the reason?
Make property instead of field
see Binding Sources Overview
Applying both ItemsSource and Datacontext not needed.