I have this XAML
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Left">
<Button
x:Name="BtnTiempo"
Content=""
Style="{StaticResource AppBaseButton}"
Padding="0"
FontSize="17"
Foreground="Red">
<Button.ContextFlyout>
<MenuFlyout x:Name="TiemposMnu">
<MenuFlyout.Items>
</MenuFlyout.Items>
</MenuFlyout>
</Button.ContextFlyout>
</Button>
<TextBlock Text="{Binding Tiempo.StrDescripcion,FallbackValue=?}" Grid.Column="1" TextAlignment="Right" Foreground="Red"/>
</StackPanel>
and this Code that fills TiemposMnu
#region Tiempos
public List<Tiempo> Tiempos
{
get { return (List<Tiempo>)GetValue(TiemposProperty); }
set { SetValue(TiemposProperty, value); }
}
// Using a DependencyProperty as the backing store for Tiempos. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TiemposProperty =
DependencyProperty.Register("Tiempos", typeof(List<Tiempo>), typeof(ItemDetallePedidoControl), new PropertyMetadata(null,new PropertyChangedCallback(OnTiemposChanged)));
private static void OnTiemposChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if(d is ItemDetallePedidoControl p)
{
if (p.Tiempos != null)
{
foreach (var tiempo in p.Tiempos)
{
MenuFlyoutItem item = new MenuFlyoutItem()
{
Text = tiempo.StrDescripcion
};
item.Click += (s, e1) =>
{
p.SeleccionarTiempo(tiempo.IntIdTiempo);
};
p.TiemposMnu.Items.Add(item);
}
}
}
}
#endregion
Everything fires ok. But when I tap / click my button doesn't shows the MenuFlyout.
What I'm doing wrong ?
But when I tap / click my button doesn't shows the MenuFlyout.
If you want to tap/click the button to show MenuFlyout you need to use Button.Flyout . Details please see the remark section.
<Button.Flyout>
<MenuFlyout x:Name="TiemposMnu">
<MenuFlyout.Items>
</MenuFlyout.Items>
</MenuFlyout>
</Button.Flyout>
If you want to trigger the MenuFlyout associate with Button.ContextFlyout, right-click (mouse) or press-and-hold (touch) directly on the button. Mode details please reference official sample.
Related
I have a datagridview populated with items and I am using a SelectionChanged event to populate textboxes from that data when selected.
If I make a selection, everything works. If I click elsewhere in the App and then come back to click the SelectionChanged event again on the same item - it doesn't work.
According to MSDN:
"This event occurs whenever there is a change to a selection."
MSDN SelectionChangedEvent
So it appears that despite clicking elsewhere, resetting the Textboxes - the selected item is not changing as the SelectionChanged event no longer triggers - click on another item and it works, click back again and it works - but click on it, reset textboxes, click it again - nothing happens, this includes clicking in the datagridview itself in a blank area.
XAML:
<DataGrid x:Name="TimeView" Grid.Row="1" Grid.Column="3"
Grid.ColumnSpan="3" Grid.RowSpan="4" Margin="10 50 10 10"
CanUserAddRows="False" Visibility="{Binding StartTiming}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cal:ActionMessage MethodName="SelectedTimeChangeEvent">
<cal:Parameter Value="$eventArgs" />
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</DataGrid>
ViewModel
public void SelectedTimeChangeEvent(SelectionChangedEventArgs e)
{
foreach (TimeData addedRow in e.AddedItems)
{
TbID = addedRow.ID;
TbDate = addedRow.Date;
TbStartTime = addedRow.StartTime;
TbDescription = addedRow.Description;
}
}
Since I am using MVVM and Caliburn, TimeView is connected to an ICollection, which is in turn connected to an ObservableCollection:
private ObservableCollection<TimeData>? _timeCollection;
public ObservableCollection<TimeData>? TimeCollection
{
get { return _timeCollection; }
set
{
_timeCollection = value;
NotifyOfPropertyChange(() => TimeCollection);
}
}
private ICollectionView? _timeView;
public ICollectionView? TimeView
{
get { return _timeView; }
set
{
_timeView = value;
NotifyOfPropertyChange(() => TimeView);
}
}
There is a work around, which is the following after populating the Textboxes:
TimeView = null;
TimeView = CollectionViewSource.GetDefaultView(TimeCollection);
This works, but I thought that there might be a "deselect" option that would be better than repopulating every time a selection is made, one of my Datagrids contains 15,000 items, and it is still instant, but seems overkill to populate it every time a selection is made.
i would recommend bindings, they automaticly reset when nothing is selected
<DockPanel>
<StackPanel DataContext="{Binding SelectedTime}" DockPanel.Dock="Left">
<TextBlock Text="{Binding ID}"/>
<TextBlock Text="{Binding Date}"/>
<TextBlock Text="{Binding StartTime}"/>
<TextBlock Text="{Binding Description}"/>
</StackPanel>
<DataGrid ItemsSource="{Binding TimeView}" SelectedItem="{Binding SelectedTime}">
...
</DataGrid>
</DockPanel>
public TimeData SelectedTime
{
get { return _selectedTime; }
set
{
_selectedTime = value;
NotifyOfPropertyChange(() => SelectedTime);
}
}
also there is this neet feature
protected virtual void SetValue<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
field = value;
OnPropertyChanged(propertyName);
}
so you can write
set { SetValue(ref _selectedTime, value) }
My application in WPF has to manage a series of windows. The main window manages the display of data acquired in real time. There are also other windows that allow you to tune parameters that change the displayed data. One of these windows consists of a slider and a textBox. The slide and the textBox bind to each other so that one updates the other. When the display is present, however, the textbox is not responsive while the slider is and this causes me a strong slowdown in the insertion of any parameters to tune.
In xaml:
<Slider Name="TAZSlider"
Grid.Column="0" Grid.Row="1"
Background="{x:Null}" mah:SliderHelper.EnableMouseWheel="MouseHover"
Orientation="Vertical"
Value="{Binding TAZValue}"
mah:SliderHelper.ThumbFillBrush="#FF9900"
mah:SliderHelper.ThumbFillHoverBrush="#faca82"
mah:SliderHelper.TrackValueFillBrush="#FF9900"
mah:SliderHelper.TrackValueFillPressedBrush="#FF9900"
mah:SliderHelper.TrackValueFillHoverBrush="#ff9900"
Maximum="{Binding TAZMax}"
Minimum="{Binding TAZMin}"
SmallChange="1"
IsSnapToTickEnabled="True"
ValueChanged="TAZSlider_ValueChanged"
AutoToolTipPlacement="TopLeft"
AutoToolTipPrecision="1"
TickFrequency="1"
ScrollViewer.PanningRatio="5"
ToolTipService.ToolTip="{Binding Path=Value, ElementName=TAZSlider}" ></Slider>
<TextBox Name="TAZTextBox" Grid.Column="0" Grid.Row="3" HorizontalAlignment="Center" Height="50" TextWrapping="Wrap" VerticalAlignment="Center" Width="100"
FontFamily="Segoe UI Symbol" FontSize="25" FontWeight="UltraBold" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Background="#FF707070" Foreground="#ececec"
Text="{Binding ElementName=TAZSlider, Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" KeyDown="TAZTextBox_KeyDown" />
C#:
public int TAZMin
{
get { return this._mainParent.tazMinimLimits;}
set { this._mainParent.tazMinimLimits = value; }
}
public int TAZMax
{
get { return this._mainParent.tazMaximumLimits; }
set { this._mainParent.tazMaximumLimits = value; }
}
public int TAZValue
{
get { return this._mainParent.tazValue; }
set { this._mainParent.tazValue = value; }
}
private void TAZSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (!isFistStart)
{
System.Diagnostics.Debug.WriteLine("[DEBUG] : Set new value (int)TAZSlider.Value " + (int)TAZSlider.Value);
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new Action(() =>
{
this._mainParent.sinaps.dataManagerTools.DAQControl.SetAZ_Period((int)TAZSlider.Value);
}));
}
}
private void TAZTextBox_KeyDown(object sender, KeyEventArgs e)
{
System.Diagnostics.Debug.WriteLine("Debug TAZTextBox_KeyDown :" + e.Key);
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Input, new Action(() => { TAZTextBox.Text = TAZTextBox.Text + "!"; }));
}
Without display everything works without having to associate the "TAZTextBox_KeyDown" event while with the display it does not. I tried to insert Dispatcher.Invoke (System.Windows.Threading.DispatcherPriority.Input, new Action (() => {TAZTextBox.Text = TAZTextBox.Text + "!";})) and that makes it distinctly responsive but sometimes it works (randomly) the keyboard entry works and therefore this causes me difficulties. Can anyone explain to me if there is a specific property of the textbox that makes keyboard input immediately responsive?
I'm trying to create an edit form for editing properties of a custom set of TV Series objects. One of the properties holds a collection of all owned media formats (DVD, Blu-ray, etc) for that particular series that will be displayed in a ComboBox. Items are added to the ComboBox via a separate popup window and items are to be removed from the ComboBox by selecting the item and clicking a remove Button.
I can add new entries to the MediaOwned ComboBox just fine, but when I try to select a specific ComboBox item to test the remove Button I find that I can only ever select the first entry. Can someone please tell me if I've missed something embarrassingly obvious, thanks.
Here is the problematic property:
private ObservableCollection<string> _mediaOwned = new ObservableCollection<string>();
public ObservableCollection<string> MediaOwned
{
get { return _mediaOwned; }
set
{
_mediaOwned = value;
OnPropertyChanged(new PropertyChangedEventArgs("MediaOwned"));
}
}
Here are the other relevant code behind:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Create binding for the ListBox.
Binding listBinding = new Binding();
listBinding.Source = show.Series;
listBinding.Mode = BindingMode.OneWay;
listBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
lbSeries.SetBinding(ListBox.ItemsSourceProperty, listBinding);
// Create binding for the ComboBox.
Binding myBinding = new Binding();
myBinding.Path = new PropertyPath("MediaOwned");
myBinding.Mode = BindingMode.TwoWay;
myBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
cbMediaOwned.SetBinding(ComboBox.ItemsSourceProperty, myBinding);
}
private void btnRemoveMedia_Click(object sender, RoutedEventArgs e)
{
Series series = (Series)lbSeries.SelectedItem;
series.MediaOwned.Remove(cbMediaOwned.Text);
}
And here is the XAML code:
<Border Style="{StaticResource PanelBorderStyle}" DockPanel.Dock="Left" Margin="0,8,8,0"
DataContext="{Binding ElementName=lbLists, Path=SelectedItem}">
<DockPanel VerticalAlignment="Top">
<StackPanel>
<ListBox x:Name="lbSeries" Style="{StaticResource BasicListStyle}" Width="180" Height="300"
DisplayMemberPath="Title" SelectionMode="Single" LayoutUpdated="lbSeries_LayoutUpdated">
</ListBox>
</StackPanel>
<StackPanel x:Name="editPanel" DataContext="{Binding ElementName=lbSeries, Path=SelectedItem}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 4, 0, 0">
<TextBlock Style="{StaticResource SmallFont}" Width="100">Title</TextBlock>
<TextBox x:Name="txtTitle" Style="{StaticResource TextBoxStyle}" Text="{Binding Path=Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="200" Margin="8, 8, 16, 8"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Top">
<TextBlock Style="{StaticResource SmallFont}" Width="100">Media owned</TextBlock>
<ComboBox x:Name="cbMediaOwned" Style="{StaticResource ComboBoxStyle}" Width="150" Margin="8,8,6,8"
></ComboBox>
<Button x:Name="btnAddMedia" Style="{StaticResource ToolbarButtonStyle}" Click="btnAddMedia_Click" Margin="0">
<StackPanel ToolTip="Add media">
<Image Source="Images/add.png" />
</StackPanel>
</Button>
<Button x:Name="btnRemoveMedia" Style="{StaticResource ToolbarButtonStyle}" Click="btnRemoveMedia_Click" Margin="4">
<StackPanel ToolTip="Remove media">
<Image Source="Images/remove.png" />
</StackPanel>
</Button>
</StackPanel>
</StackPanel>
</DockPanel>
</Border>
Alternatively I can also remove the binding code in the code behind and replace the ComboBox with the below code (but I still get the same problem - I can't select anything in the ComboBox):
<ComboBox x:Name="cbMediaOwned" Style="{StaticResource ComboBoxStyle}" Width="150" Margin="8,8,6,8" ItemsSource="{Binding ElementName=lbSeries, Path=SelectedItem.MediaOwned, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectedMedia, UpdateSourceTrigger=PropertyChanged}"></ComboBox>
SelectedMedia property:
private string _selectedMedia = "";
public string SelectedMedia
{
get { return _selectedMedia; }
set
{
_selectedMedia = value;
OnPropertyChanged(new PropertyChangedEventArgs("SelectedMedia"));
}
}
Here is my xaml:
<ComboBox x:Name="Models_ComboBox"
Width="110"
Text="Model"
ItemsSource="{Binding Models}"
SelectedItem="{Binding SelectedModel}"
DisplayMemberPath="Model"
MouseDoubleClick="Models_ComboBox_MouseDoubleClick"
SelectionChanged="Models_ComboBox_SelectionChanged"/>
Here are my VM properties:
private DataTable models;
public DataTable Models
{
get { return models; }
set
{
if (models != value)
{
models = value;
OnPropertyChanged(nameof(Models));
}
}
}
and
private DataRowView selectedModel;
public DataRowView SelectedModel
{
get { return selectedModel; }
set
{
if (selectedModel != value)
{
selectedModel = value;
if (value != null)
{
InitializeOptions(value["Model"].ToString());
}
OnPropertyChanged(nameof(SelectedModel));
}
}
}
As you can see, the ItemsSource and the SelectedItem of the ComboBox are bound to two different properties in the ViewModel. The ItemsSource is bound to a DataTable populated from a Database. Once the user selects a Model, then there are other option ComboBoxes that are populated based on that selection.
Fixed the problem myself. I had a line of code that was automatically setting the SelectedIndex of the ComboBox without me realizing.
I am pretty new to WPF and I have tried figuring out how to add a Label appear inside a the following ListView which shows the number of Items currently in the ListView. I've given the ListView padding on the top to make room for the Label.
<ListView x:Name="MyListView" Grid.Row="0" Grid.Column="0" Margin="0,40,0,0" Padding="0" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBlock Text="{Binding DatasetCode}" FontWeight="Bold"/>
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
If anyone can help me out, it would be greatly appreciated.
Edit the Template of ListBox. You can do this by Right-Clicking the ListBox in the Document outline section. And add your Label as below.
...
<ScrollViewer Focusable="false" Padding="{TemplateBinding Padding}">
<StackPanel>
<Label uc:Window2.CountFor="False" />
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</StackPanel>
</ScrollViewer>
...
I have written an attached property CountFor . Code is give below :
#region CountFor attached property
public static bool GetCountFor(DependencyObject obj)
{
return (bool)obj.GetValue(CountForProperty);
}
public static void SetCountFor(DependencyObject obj, bool value)
{
obj.SetValue(CountForProperty, value);
}
// Using a DependencyProperty as the backing store for CountFor. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CountForProperty =
DependencyProperty.RegisterAttached("CountFor", typeof(bool), typeof(Window2), new PropertyMetadata(false, new PropertyChangedCallback(GetCountForChanged)));
private static void GetCountForChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue == false) return;
Label lbl = (Label)d;
lbl.Loaded += (o, args) =>
{
DependencyObject parent = VisualTreeHelper.GetParent(lbl);
while (parent.GetType() != typeof(ListBox))
parent = VisualTreeHelper.GetParent(parent);
ListBox lb = (ListBox)parent;
ICollectionView view = CollectionViewSource.GetDefaultView(lb.ItemsSource);
lbl.Content = "Number of items = " + ((ListCollectionView)view).Count;
view.CollectionChanged += (col, colargs) =>
{
lbl.Content = "Number of items = " + ((ListCollectionView)col).Count;
System.Diagnostics.Debug.WriteLine(((ListCollectionView)col).Count.ToString());
};
};
}
#endregion
Your solution is simple, you could just create an int to count the number of items in your label and then assign a new textblock, you could also completely skip the textblock and simply add the int, check this code:
private void button1_Click(object sender, RoutedEventArgs e)
{
int testcounter;
testcounter = listBox.Items.Count;
TextBlock BlockCounter = new TextBlock();
BlockCounter.Text = testcounter.ToString();
listBox.Items.Add(BlockCounter);
}
I need to change the display order of the text in my UWP app but unfortunately I don't find any straight solution to do so.
The textblock in WinRT does not support this property, at least I can't found any information about this feature from MSDN. I found a solution that I need create a "New" textblock control which supports the text display in vertical order but the solution is for silverlight so I'm working on it to see whether it works or not.
This is how textblock works normally:
This is how textblock that I want it to work:
I know there is a way that just setting up the Width and text wraping something but it only works for a certain screen size & resolution, which means under other screen the text will not display properly
Any tips would be appreciated.
To get a "real" vertical text in UWP try the following:
<TextBlock Text="Rotated Text"
FontSize="18"
Foreground="Black">
<TextBlock.RenderTransform>
<RotateTransform Angle="-90" />
</TextBlock.RenderTransform>
</TextBlock>
Edit - UWP verison with user control
VerticalTextBlock - code behind
public partial class VerticalTextBlock : UserControl
{
public VerticalTextBlock()
{
InitializeComponent();
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text",
typeof(string),
typeof(VerticalTextBlock),
new PropertyMetadata(string.Empty, textChangeHandler));
private static void textChangeHandler(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var prop = d as VerticalTextBlock;
var textBlock = prop.TheTextBlock;
var str = (e.NewValue as string);
textBlock.Inlines.Clear();
for (int i = 0; i < str.Length-1; i++)
{
textBlock.Inlines.Add(new Run() { Text = str[i] + Environment.NewLine });
}
textBlock.Inlines.Add(new Run() { Text = str[str.Length-1].ToString()});
}
}
VerticalTextBlock - XAML
<UserControl
...
>
<TextBlock x:Name="TheTextBlock"/>
</UserControl>
Usage and test - XAML
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock x:Name="a" Text="ASD"></TextBlock>
<local:VerticalTextBlock x:Name="b" Text="{Binding ElementName=a, Path=Text}" />
<local:VerticalTextBlock x:Name="c" Text="{Binding ElementName=b, Path=Text}" />
<TextBlock x:Name="d" Text="{Binding ElementName=c, Path=Text}"></TextBlock>
<TextBlock TextAlignment="Center" HorizontalAlignment="Left">
<Run Text="A"/>
<LineBreak/>
<Run Text="S"/>
<LineBreak/>
<Run Text="D"/>
<LineBreak/>
<Run Text="A"/>
<LineBreak/>
<Run Text="S"/>
<LineBreak/>
<Run Text="D"/>
</TextBlock>
</StackPanel>
Original Answer - didn't notice it's UWP not WPF
You got me interested as I've only done this in Android, so there are a few solutions that will work but I decided to try custom control extending TextBlock
public partial class VerticalTextBlock : TextBlock
{
public VerticalTextBlock()
{
InitializeComponent();
}
new public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
new public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text",
typeof(string),
typeof(VerticalTextBlock),
new PropertyMetadata(string.Empty, textChangeHandler));
private static void textChangeHandler(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var prop = d as VerticalTextBlock;
var str = (e.NewValue as string);
var inlines = str.Select(x => new Run(x + Environment.NewLine));
prop.Inlines.Clear();
prop.Inlines.AddRange(inlines);
}
}
Usage in XAML
<local:VerticalTextBlock Text="AABBCCDDEEFF" />