How do I get the user selection item from a ComboBox in WinUI3 C++/WinRT? - c++-winrt

I would like to get the selected user item from a ComboBox in WinUI3 C++/WinRT.
There is this code in XAML:
<ComboBox x:Name="ComboTranslate" HorizontalAlignment="Center" Header="Translate to" SelectionChanged="ComboBox_SelectionChanged" SelectedIndex="0" Width="200" Margin="0,15,0,0">
<x:String>2</x:String>
<x:String>8</x:String>
<x:String>10</x:String>
<x:String>16</x:String>
</ComboBox>
In C# in WinUI3 it is implemented as follows:
private void ColorComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Add "using Windows.UI;" for Color and Colors.
string colorName = e.AddedItems[0].ToString();
Color color;
switch (colorName)
{
case "Yellow":
color = Colors.Yellow;
break;
case "Green":
color = Colors.Green;
break;
case "Blue":
color = Colors.Blue;
break;
case "Red":
color = Colors.Red;
break;
}
colorRectangle.Fill = new SolidColorBrush(color);
}
How can you do this on C++/WinRT?

Here's how I'm doing it on my pet project's PopUpButton class, using the SelectedIndex() method:
void
CAUIPopUpButton::HandleHostSelectionChangedEvent(
Windows::Foundation::IInspectable const & /* sender */,
Windows::UI::Xaml::Controls::SelectionChangedEventArgs const & /* event */ )
{
M_LOG_METHOD( HandleHostSelectionChangedEvent )
TIndex newSelectedItem;
newSelectedItem = _hUIElement.as< Windows::UI::Xaml::Controls::ComboBox >().SelectedIndex();
ValueChanged( newSelectedItem );
}
Basically, I'm not using the information of the sender and event as I manually connect the event handler to the ComboBox, the _hUIElement in the code above.
_hUIElement = Windows::UI::Xaml::Controls::ComboBox();
_hUIElement.as< Windows::UI::Xaml::Controls::ComboBox >().SelectionChanged( { this, & CAUIPopUpButton::HandleHostSelectionChangedEvent } );
Please don't judge my C++ style: I'm a bit old school and not a big fan of XAML !

Related

How can I conditionally use two different flyout menus in my UserControl in UWp

I have a UserControl that contains a button, and when the button is clicked, a flyout menu should appear. However, I would like to use different flyout menus depending on a specific condition.
I have created a dependency property in my UserControl that determines which flyout menu to display, and a converter that converts the value of the dependency property to the corresponding flyout menu.
How do I change the value of dependency property from the view
The most direct way to do this is modify the MenuFlyout object in the code behind. You could change the items of the MenuFlyout manually based on the specific condition.
I notice that you are creating in the converter. So want you need to do is to create the MenuFlyoutItems in the converter.
Here is a simple demo which I made. The button's MenuFlyout will change after another button is clicked.
Xaml:
<StackPanel>
<Button x:Name="MyButton" Content="Click" >
<Button.Flyout>
<MenuFlyout x:Name="TestFlyout">
<MenuFlyoutItem Text="Change color" />
</MenuFlyout>
</Button.Flyout>
</Button>
<Button Content="ChangeMenuItem" Click="MyButton_Click"/>
</StackPanel>
Code-behind:
bool testFlag= false;
public MainPage()
{
this.InitializeComponent();
}
private void MyButton_Click(object sender, RoutedEventArgs e)
{
if (testFlag)
{
GenerateItemA();
testFlag = false;
}
else
{
GenerateItemB();
testFlag = true;
}
}
private void GenerateItemA()
{
// remove all the existing items
TestFlyout.Items.Clear();
TestFlyout.Items.Add(new MenuFlyoutItem { Text = "Group A" });
TestFlyout.Items.Add(new MenuFlyoutItem { Text = "Group B" });
TestFlyout.Items.Add(new MenuFlyoutItem { Text = "Group c" });
}
private void GenerateItemB()
{
// remove all the existing items
TestFlyout.Items.Clear();
TestFlyout.Items.Add(new MenuFlyoutItem { Text = "Group 123" });
TestFlyout.Items.Add(new MenuFlyoutItem { Text = "Group 234" });
TestFlyout.Items.Add(new MenuFlyoutItem { Text = "Group 435" });
}

MasterDetailView UWP - Access the ListView (or make it scroll)

I recently discovered the UWP Community Toolkit and I loved it. I'm using now the MasterDetailView and it's almost perfect for what I need: but it's missing one important thing: I cannot access the internal "ListView".
In my application I have two buttons: forward and back, and when pressing them I simply go forward and back in the list. I found a trick to access the prev/next element doing like this:
public void GoForward()
{
if (MasterDetailView.Items.Count > 0)
{
bool isNextGood = false;
MyItem selectedItem = MasterDetailView.Items[MasterDetailView.Items.Count - 1] as MyItem;
foreach (var v in MasterDetailView.Items)
{
if (isNextGood)
{
selectedItem = v as MyItem;
break;
}
if (v == MasterDetailView.SelectedItem)
isNextGood = true;
}
MasterDetailView.SelectedItem = selectedItem;
}
}
This just because I cannot access the "SelectedIndex" and I have only SelectedItem avaiable. Now, obviously not all the item can be visible at the same time, so MasterDetailView provide a lateral ListView with a scrollbar. When pressing my next/prev buttons SelectedItem changes, but doesn't scroll at the selected element: selection goes forward/back but the list is locked. This produce a very negative feedback because I lost my selection somewhere in the list and I must search it.
How I though to solve it? I try this approaches:
1) Find the style for MasterDetailView. Inside I found a ListViewStyle, so I tried to put inside a simple "SelectionChanged" event and handle it at App.xaml.cs.
<ListView x:Name="MasterList"
Grid.Row="1"
IsTabStop="False"
ItemContainerStyle="{TemplateBinding ItemContainerStyle}"
ItemTemplate="{TemplateBinding ItemTemplate}"
ItemTemplateSelector="{TemplateBinding ItemTemplateSelector}"
ItemsSource="{TemplateBinding ItemsSource}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
SelectionChanged="MasterList_SelectionChanged"/>
CS:
private void MasterList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListView list = sender as ListView;
list.ScrollIntoView(list.SelectedItem);
}
But, as said, "Events cannot be set in the Application class XAML file".
2) Think about taking the parent of SelectedItem: I tried to convert the SelectedItem in ListViewItem, then access the parent, but it fails at first conversion, as the SelectedItem seems no to be a ListViewItem, but it's of the "MyItem" type. Like this, I cannot access the parent.
private void MasterDetailView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var item = MasterDetailView.SelectedItem as ListViewItem;
var parent = item.Parent;
var list = parent as ListView;
}
And so I'm here... I don't want to throw away all my work with the MasterDetailView to pass to another control. Is there any simple method to access the list, or simply, scroll the list when I'm changing selection? Just wanna to do one thing, like this:
private void List_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListView list = sender as ListView;
list.ScrollIntoView(list.SelectedItem);
}
Simply scrolling into selection when selection changed occurred, but I have no simple ListView but a MasterDetailView control. Even if it's done entirely in XAML: the most important thing for me is make scroll this list!
Thanks.
 
 
Solution
This method is fantastic. Just copy-paste.
public static T FindChildOfType<T>(DependencyObject root) where T : class
{
var queue = new Queue<DependencyObject>();
queue.Enqueue(root);
while (queue.Count > 0)
{
DependencyObject current = queue.Dequeue();
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(current); i++)
{
var child = VisualTreeHelper.GetChild(current, i);
var typedChild = child as T;
if (typedChild != null)
{
return typedChild;
}
queue.Enqueue(child);
}
}
return null;
}
Then simply use it to retrive the list and make it scroll. Yes babe!
private void MasterDetailView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var v = FindChildOfType<ListView>(MasterDetailView);
v.ScrollIntoView(MasterDetailView.SelectedItem);
}
Please note that "MasterDerailView" Is the x:Name of my element, not the class.
You can use a FindChildOfType implementation to get the ListView through VisualTreeHelper, as indicated in this answer:
Windows UWP - How to programmatically scroll ListView in ContentTemplate

I need a event for the slider it should fire only if user ends touching the control

My Requriment : I need a event for slider it should fire only if user ends touching the control
Custom Control :
public class ExtendedSlider : Slider
{
public event EventHandler StopedDraging;
public void OnStopedDrag()
{
if (StopedDraging != null)
{
StopedDraging(this,EventArgs.Empty);
}
}
}
UI :
<ListView.ItemTemplate >
<Label Text="{Binding luminaireLevel, StringFormat='{0:F0}%'}" />
<PCAControls:ExtendedSlider Maximum="100" Minimum="25"
Value="{Binding luminaireLevel, Mode=TwoWay}"
LuminaireID="{Binding id}"
StopedDraging="ExtendedSlider_StopedDraging"
/>
</ListView.ItemTemplate>
Renderer :
class ExtendedSliderRenderer : SliderRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Slider> e)
{
base.OnElementChanged(e);
if (Control != null)
{
var slider = (PCA.CustomControls.ExtendedSlider)e.NewElement;
Control.Max = (int)(slider.Maximum - slider.Minimum);
Control.Progress = (int)(slider.Value - slider.Minimum);
Control.StopTrackingTouch += Control_StopTrackingTouch;
}
}
void Control_StopTrackingTouch(object sender, SeekBar.StopTrackingTouchEventArgs e)
{
var slider = (PCA.CustomControls.ExtendedSlider)Element;
slider.Value = Control.Progress + slider.Minimum;
slider.OnStopedDrag();
}
}
Problem is : I achieved what i expected, but user stop draging the slider or tap between the slider , luminaireLevel (vewmodel property) is updating but the slider always showing the full progess
When your renderer changes the value of the iOS control the "binding" isn't Two=Way in that respect. To achieve what you want you need to bind the Xamarin.Forms Slider to value in your viewmodel then in your renderer you change the value in your viewmodel.
If you bind all your properties (min, max, value, progress) itll be easier

Windows Phone 8.1 RT: how to prevent manipulation event throw object?

I'm new C# beginer. I want to prevent throwing XAML's object by manipulation event. My app is developed in Windows Phone 8.1 RT.
I have XAML's REctangle:
<Canvas x:Name="MyCanvas" Background="White">
<Rectangle Name="TestRectangle"
Width="100" Height="200" Fill="Blue"
ManipulationMode="All"/>
</Canvas>
In MainPage:
public MainPage()
{
this.InitializeComponent();
// Handle manipulation events.
TestRectangle.ManipulationDelta += Drag_ManipulationDelta;
dragTranslation = new TranslateTransform();
TestRectangle.RenderTransform = this.dragTranslation;
this.NavigationCacheMode = NavigationCacheMode.Required;
}
void Drag_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
// Move the rectangle.
dragTranslation.X += e.Delta.Translation.X;
dragTranslation.Y += e.Delta.Translation.Y;
}
private void TestRectangle_PointerPressed(object sender,
PointerRoutedEventArgs e)
{
Rectangle rect = sender as Rectangle;
// Change the size of the Rectangle
if (null != rect)
{
rect.Width = 250;
rect.Height = 150;
}
}
private void TestRectangle_PointerReleased(object sender,
PointerRoutedEventArgs e)
{
Rectangle rect = sender as Rectangle;
// Reset the dimensions on the Rectangle
if (null != rect)
{
rect.Width = 200;
rect.Height = 100;
}
}
private void TestRectangle_PointerExited(object sender,
PointerRoutedEventArgs e)
{
Rectangle rect = sender as Rectangle;
// Finger moved out of Rectangle before the pointer exited event
// Reset the dimensions on the Rectangle
if (null != rect)
{
rect.Width = 200;
rect.Height = 100;
}
}
How to move object whitout throwing when user exit event ?
I'm assuming that by 'throwing' you mean you want to remove the inertial aspect of your rectangle? In that case remove the ManipulationMode setter from your XAML code and insert this line in your page's constructor (C#):
TestRectangle.ManipulationMode = ManipulationMode.TranslateX | ManipulationMode.TranslateY;
That should remove the intertial effect you're talking about. As a side note though, this method of moving UIElements will give you a pretty annoying lag. I faced a similar problem a little while ago and the issue was resolved by using a different approach:
Delay in drag/drop of UIElement in Windows Phone 8.1

Autocompletebox SelectedText Bug

I want to bind both the SelectedText and SelectedItem properties of an AutocompleteBox because my client wants to be able to input text and select from the list also. It's working properly but ...
The MainPage has one DataGrid. When I select a record from the Grid (i.e. SelectedItem), I want to set it in a popup window's AutocompleteBox. Some times it works but some times it doesn't.
What should I do for this issue?
This is my XAML:
<Sdk:AutoCompleteBox Grid.Column="3" Grid.Row="3" Height="18" Width="150"
IsTextCompletionEnabled="True" TabIndex="9" HorizontalAlignment="Left"
Text="{Binding ElementName=ResEdit,Path=DataContext.SelectedDemoText,Mode=TwoWay}"
ItemsSource="{Binding ElementName=ResEdit,Path=DataContext.DemoList,Mode=OneWay}"
ItemTemplate="{StaticResource DemoTemplate}"
ValueMemberPath="DemoCode"
LostFocus="AutoCompleteBox_LostFocus"
Margin="0,0,21,0" Padding="0">
</Sdk:AutoCompleteBox>
This property is in my view-model and bound to the DataGrid:
public InvoicesDTO SelectedInvoice
{
get { return _selectedInvoice; }
set
{
SelectedInvoice = value;
SelectedDomoText = SelectedInvoice.DemoText.Trim();
RaisePropertyChanged("SelectedInvoice");
}
}
You should not use both function SelectedText and SelectedItem in autocomplete. it's a bug of AutoCompleteBox..... A better way is to set the visiblity of the textbox and AutoCompleteBox on GotFocus and LossFocus. This Way You Will Defiantly Solve You Problem
private void DemoAutoComplete_LostFocus(object sender, RoutedEventArgs e)
{
DemoTextBox.Visibility = Visibility.Visible;
DemoAutoComplete.Visibility = Visibility.Collapsed;
DemoTextBox.Text = OCRAutoComplete.Text;
((DemoVM)this.DataContext).SelectedDemoText = DemoAutoComplete.Text;
}
private void DemoTextBox_GotFocus(object sender, RoutedEventArgs e)
{
DemoAutoComplete.Text = OctTextBox.Text;
DemoTextBox.Visibility = Visibility.Collapsed;
DemoAutoComplete.Visibility = Visibility.Visible;
DemoAutoComplete.Focus();
}