I'm learning WPF and I have some troubles with it. I made this XAML:
<Window.Resources>
<DataTemplate x:Key="TemplateTest">
<Button Margin="10"
BorderThickness="2"
Content="{Binding Path=Text}">
<Button.Effect>
<DropShadowEffect BlurRadius="20" />
</Button.Effect>
</Button>
</DataTemplate>
</Window.Resources>
<StackPanel x:Name="StackPanel">
<TextBox x:Name="TextBox"
Margin="10">TextBox</TextBox>
<ContentControl Content="{Binding ElementName=TextBox, Path=.}"
ContentTemplate="{StaticResource ResourceKey=TemplateTest}" />
</StackPanel>
and the code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var Resource = this.Resources["TemplateTest"] as DataTemplate;
StackPanel.Children.Add(
new ContentControl()
{
Content = new Binding()
{
ElementName = "TextBox",
Path = new PropertyPath(".")
},
ContentTemplate = Resource,
});
}
}
My problem is that the textbox's text only appear in the XAML defined control.
How to make it work in the code behind too?
You're setting the ContentControl.Content to the Binding, which is not the same as binding the Content property to a value.
To bind a property in the code behind, you need syntax like this:
var newControl new ContentControl();
newControl.ContentTemplate = Resource;
Binding b = new Binding();
b.ElementName = "TextBox";
b.Path = new PropertyPath(".");
myContentControl.SetBinding(ContentControl.ContentProperty, b);
Related
I have a wpf application in c# and my problem is now I have a Listbox with bindings and my question is how can I get the text from the textbox in the Listbox?
My Listbox XAML:
<ListBox x:Name="chats_lb_friends" ItemsSource="{Binding Friends_pic}" Height="870" Width="280" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="#FF535664" FontSize="18" FontFamily="/Nextopia Launcher v.2.0;component/fonts/#Mont DEMO" FontWeight="Bold" IsSynchronizedWithCurrentItem="False" MinWidth="280" SelectionChanged="chats_lb_friends_SelectionChanged_1">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="chats_lb_friends_stackpanel" Orientation="Horizontal">
<Ellipse x:Name="chats_lb_friends_img" Width="25" Height="25" Stroke="{Binding status}" StrokeThickness="2">
<Ellipse.Fill>
<ImageBrush Stretch="Fill" ImageSource="{Binding imagePath}"/>
</Ellipse.Fill>
</Ellipse>
<TextBlock x:Name="chats_lb_friends_txt" Text="{Binding username}" Margin="5,0,0,0" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
What do I want:
ListBoxItem MyItem = chats_lb_friends.SelectedItem as ListBoxItem;
if(MyItem != null)
{
StackPanel sp = MyItem.Content as StackPanel;
if(sp != null && sp.Children.Count > 0)
{
TextBlock textBlock = sp.Children[0] as TextBlock;
if(textBlock != null)
{
string text = textBlock.Text;
}
}
}
But this is not working have anyone an idea why?
Thanks in the advance and sorry for my English
Assuming you have a PersonViewModel with a public string property username.
The itemssource of your lisbox doesn't seem to be bound. But let's assume you can have a window viewmodel with 2 public properties:
public ObservableCollection<PersonViewModel> People {get;set;} = new ObservableCollection<PersonViewModel>()
public PersonViewModel SelectedPerson {get;set;}
So you can bind SelectedItem of the listBox to SelectedPerson
<ListBox SelectedItem="{Binding SelectedPerson" ItemsSource="{Binding People}"
Then you can do:
var name = SelectedPerson.username;
You will also want some null checking maybe
var name = SelectedPerson?.username ?? "";
You should implement inotifypropertychanged on all viewmodels and you will also likely to want to raise notifypropertychanged from the setters of your viewmodel properties.
More about working with selected items using mvvm here:
https://social.technet.microsoft.com/wiki/contents/articles/30564.wpf-uneventful-mvvm.aspx#Select_From_List_IndexChanged
I'm trying to dynamically bind a Flyout content to a view, like I would do to a TabControl, but when I load the view object the Flyout is empty. I tried loading the view directly below the Controls:FlyoutsControl and it worked, so I don't think the problem is with the view itself.
Also, I need to load this in a specific Flyout, so using the ItemSource property in the Controls:FlyoutsControl wouldn't work for me.
MainWindow.xml
<Controls:MetroWindow.Flyouts>
<Controls:FlyoutsControl>
<Controls:Flyout
Content="{Binding FlyTest, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsOpen="{Binding IsOpen, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Background="#91000000"/>
</Controls:FlyoutsControl>
</Controls:MetroWindow.Flyouts>
UserControl1.xml - The View to be loaded
<controls:Flyout
x:Class="TestApp.View.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
Position="Right"
MinWidth="380" MaxWidth="380"
Header="Manufacturer Data">
<Grid>
<TextBox
Text="Test Data"
Grid.Row="0" Grid.Column="0"
VerticalAlignment="Center"
HorizontalAlignment="Right"/>
</Grid>
</controls:Flyout>
MainWindowViewModel.cs
private UserControl1 _flyTest;
public UserControl1 FlyTest
{
get { return _flyTest; }
set
{
_flyTest = value;
RaisePropertyChanged("FlyTest");
}
}
private void LoadTabs()
{
FlyTest = new UserControl1();
IsOpen = true;
}
I figured it out by changing the view object type from Flyout to UserControl
My MainWindow.xaml get it´s datacontext from MyClass.cs and it´s view from usercontrol in MyView.xaml as below
<Window.DataContext>
<ViewModel:MyClass/>
</Window.DataContext>
<View:MyView/>
The usercontrol has grid, stackpanel and a button as below
<Grid x:Name="MainGrid" Height="300" Width="502">
<StackPanel x:Name="MainStackPanel" Height="200" Width="400"/>
<Button x:Name="NewButton" Command="{Binding CommandAddNewButton}" Content="new item" Height="25" Width="55" Margin="224,177,223,98"/>
</Grid>
From MyClass I try to add button and textbox to the stackpanel programatically by pressing the "new item" button as below
public ICommand CommandAddNewButton
{ get { return new MyCommand(AddNewButton); } }
private void AddNewButton()
{
var newButton = new Button
{
Name = "Button" + _itemNbr,
Content = "-",
FontSize = 10,
Height = 20,
Width = 15,
Background = new SolidColorBrush(Colors.Beige),
HorizontalContentAlignment = HorizontalAlignment.Center,
VerticalContentAlignment = VerticalAlignment.Center,
Margin = new Thickness(10, 10, 10, 10)
};
var newTextBox = new TextBox
{
Name = "TextBox" + _itemNbr,
Height = 20,
Width = 70,
FontSize = 10,
HorizontalContentAlignment = HorizontalAlignment.Right,
VerticalContentAlignment = VerticalAlignment.Center
};
MainStackPanel.Children.Add(newButton);
MainStackPanel.Children.Add(newTextBox);
}
A new button and textboxe are created after button press but they do not displayed. How can I fix it? All help are appreciated.
<UserControl x:Class="WpfApp1.View.MyView"
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:ViewModel="clr-namespace:WpfApp1.ViewModel"
xmlns:View="clr-namespace:WpfApp1.View">
<Grid x:Name="MainGrid" Height="300" Width="502">
<StackPanel x:Name="MainStackPanel" Height="200" Width="400"/>
<Button x:Name="NewButton" Command="{Binding CommandAddNewButton}" Content="new item" Height="25" Width="55" Margin="224,177,223,98"/>
</Grid>
</UserControl>
I think you are inheriting your View(Myview) to your viewmodel(Myclass). so that you are accessing a different instance of stackpanel. One method you can do is pass stackpanel as a paramater to the view model .
In Xaml:
<Button x:Name="NewButton" Command="{Binding CommandAddNewButton}" CommandParameter="{Binding ElementName=MainStackPanel}" Content="new item" Height="25" Width="55" Margin="224,177,223,98"/>
In ViewModel:
private void AddNewButton(object obj)
{
var MainStackPanel= obj as StackPanel;
}
I have the code in XAML:
<Button Grid.Column="0" Grid.Row="1" x:Name="btnSete" Click="btn_Click">
<ContentControl.Content>
<Viewbox Margin="3">
<TextBlock Text="7"/>
</Viewbox>
</ContentControl.Content>
</Button>
And code behind:
private void btn_Click(object sender, RoutedEventArgs e)
{
Button btn = (Button)e.Source;
txbDisplay.Text = btn.Content.ToString();
}
how do I get the value of <TextBlock Text="7"/> in btn_Click?
Based on your XAML, btn.Content should be the instance of the Viewbox. Then the Child property of the Viewbox should be your TextBlock.
So you should be able to do this (inside your button click event handler):
var viewBox = (Viewbox)btn.Content;
var textBlock = (TextBlock)viewBox.Child;
var text = textBlock.Text; // This is the value you were looking for
txbDisplay.Text = text;
Also, just as a helpful note, the <ContentControl.Content> ... </ContentControl.Content> part of your XAML is superfluous. That block could just be written as:
<Button Grid.Column="0" Grid.Row="1" x:Name="btnSete" Click="btn_Click">
<Viewbox Margin="3">
<TextBlock Text="7"/>
</Viewbox>
</Button>
See the "XAML Content Properties" section on this page for more information why that is if you're not sure.
I have a WPF toolkit grid with rowdetails property turned on.
My rowdetails template is as follows
<DataTemplate x:Key="rowDetailsTemplate">
<Border BorderBrush="Black" BorderThickness="1" Background="#BFEFF2F5">
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Vertical">
<ListBox Margin="100, 0, 0, 0" ItemsSource ="{Binding Path=GridSubItems}">
</ListBox>
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
Where GridSubItems defined in code behind:
public class GridDataSource
{
private List<GridItemData> _GridItems = new List<GridItemData>();
private List<GridItemData> _GridSubItems = new List<GridItemData>();
public List<GridItemData> GridItems
{
get
{
return _GridItems;
}
set
{
_GridItems = value;
}
}
public List<GridItemData> GridSubItems
{
get
{
return _GridSubItems;
}
set
{
_GridSubItems = value;
}
}
}
and its data defined in XAML:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:myapp="clr-namespace:MyControlsDemo.DemoResources"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<myapp:GridDataSource x:Key="dgs">
<myapp:GridDataSource.GridItems>
<myapp:GridItemData Name="Item1" Type="Numeric" Unit="MHz" Key="i1" />
<myapp:GridItemData Name="Item2" Type="List" Unit="enum" Key="i2" />
<myapp:GridItemData Name="Item3" Type="Text" Unit="text" Key="i3" />
</myapp:GridDataSource.GridItems>
<myapp:GridDataSource.GridSubItems>
<myapp:GridItemData Name="SubItem1" Type="Numeric" Unit="MHz" Key="si1" />
<myapp:GridItemData Name="SubItem2" Type="Numeric" Unit="MHz" Key="si2" />
<myapp:GridItemData Name="SubItem3" Type="Numeric" Unit="MHz" Key="si3" />
</myapp:GridDataSource.GridSubItems>
</myapp:GridDataSource>
And that is how this datatemplate is used:
<ContentControl Grid.Column="2">
<centerpanel:GenericParametersGrid DataContext="{StaticResource dgs}"
ItemsSource="{Binding Path=GridItems}"
RowDetailsTemplate="{StaticResource ResourceKey=rowDetailsTemplate}"
Style="{StaticResource ResourceKey=centerPanelHierParameterGridStyle}"/>
</ContentControl>
However I cannot see subitems in my application, the listbox is shown empty.
If I define subitems directly inside datatemplate, I can see them, so I guess the problem is in my data binding, but for the life of me I cannot see what is wrong. I should admit I have a very short experience with WPF.
Thanks a lot for any advice.
flot
GridSubItems has to be a Property of the ItemsSource for your DataGrid binding. otherwise you have to go with RelativeSource in your RowDetailsDataTemplate. but then its not real a child relation...
<DataGrid ItemsSource="{Binding MyDataWithAlsoAPropertyGridSubItems}">
//Columns...
//RowDetailsTemplate with Binding to GridSubItems
</DataGrid>
EDIT: in your case your GridItemData object need a public property GridSubItems to work with RowDetailsTemplate straightforward