Size of the Custom popup window using Interaction request - prism

I used a custom confirmation popup window, this the XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding Content}" TextWrapping="Wrap" Width="150"/>
<StackPanel Orientation="Horizontal" Margin="6" Grid.Row="1">
<Button x:Name="YesBtn" Width="100" Content="OK" Click="OnOk_Click"/>
<Button x:Name="NoBtn" Width="100" Content="No" Click="OnNo_Click"/>
</StackPanel>
</Grid>
and this is the code behide:
public partial class CustomConfirmation : IInteractionRequestAware
{
public CustomConfirmation()
{
InitializeComponent();
}
public IConfirmation Confirmation
{
get { return this.DataContext as IConfirmation; }
set { this.DataContext = value; }
}
public string Title { get; set; }
public bool Confirmed { get; set; }
public INotification Notification { get; set; }
public Action FinishInteraction { get; set; }
private void OnOk_Click(object sender, RoutedEventArgs e)
{
if (FinishInteraction != null)
{
Confirmation.Confirmed= true;
FinishInteraction();
}
}
private void OnNo_Click(object sender, RoutedEventArgs e)
{
if (FinishInteraction != null)
{
Confirmation.Confirmed = false;
FinishInteraction();
}
}
}
In view model class i have :
two commands(DispalyLongTextCommand and DispalyShortTextCommand): one
to display long message and the other to display a short message
and i have InteractionRequest ConfirmationRequest
object initialized in ctor to raise intercations.
if I display the long message first my custom window resize its content to the hole message, it is OK!
but if a want to display the short message, my window keeps the previous size!
note : even i set the window SizeToContent style to WidthAndHeight but it not working.
<ei:Interaction.Triggers>
<prism:InteractionRequestTrigger SourceObject="{Binding ConfirmationRequest, Mode=TwoWay}">
<prism:PopupWindowAction IsModal="True" CenterOverAssociatedObject="True">
<prism:PopupWindowAction.WindowStyle>
<Style TargetType="Window">
<Setter Property="SizeToContent" Value="WidthAndHeight"/>
</Style>
</prism:PopupWindowAction.WindowStyle>
<prism:PopupWindowAction.WindowContent>
<local:CustomConfirmation/>
</prism:PopupWindowAction.WindowContent>
</prism:PopupWindowAction>
</prism:InteractionRequestTrigger>
</ei:Interaction.Triggers>
can you guide me,
thanks in advance
SOLUTION:
I fixed the problem by adding this code in the code behind of the custom popup window, :
public CustomConfirmationView()
{
InitializeComponent();
Loaded += CustomPopupView_Loaded;
}
private void CustomPopupView_Loaded(object sender, RoutedEventArgs e)
{
var parentWindow = this.Parent as Window;
if (parentWindow != null)
{
parentWindow.Measure(parentWindow.DesiredSize);
}
}

The WindowContent property is reused each time you show a new popup. So, what happens is that when you first show a popup, the CustomPopupView is visualized and the height is set based on the current content. Now, when you close the popup, and change the content to a larger message and then show it again, the CustomPopupView.Height has already been set by the previous action and isn't updated in time for the new Window to get the correct height. So you must now resize the Window to match the new size of the CustomPopupView height. So just add a little code to handle this in your code-behind like this:
public CustomPopupView()
{
InitializeComponent();
Loaded += CustomPopupView_Loaded;
}
private void CustomPopupView_Loaded(object sender, RoutedEventArgs e)
{
var parentWindow = this.Parent as Window;
if (parentWindow != null)
parentWindow.MinHeight = _txt.ActualHeight + 75;
}
Note: '_txt' is the name of the TextBlock with the Content binding.

I think this has to do with the default confirmation window that ships with Prism. The MinWidth and MinHeight are set in the XAML to 300 and 150, respectively. So, the window width/weight will never get any smaller no matter what the window content is. Overriding the window style will not be enough to do what you need.
You could download the Prism code and remove that limitation if you are comfortable enough with that. The source path to the file you would want to start with is below.
\Source\Wpf\Prism.Wpf\Interactivity\DefaultPopupWindows\DefaultConfirmationWindow.xaml
Either that, or ask the Prism team to see if they can make this more flexible, which is probably a better suggestion. You can post this as an issue on their GitHub page. https://github.com/PrismLibrary/Prism/issues

Related

[UWP How to get control of a UserControl placed inside a ListView without altering the listview binding source?

I have placed a UserControl inside a ListView.
How do I get the control of this UserControl in the view.
If I place it inside a ListView, I am unable to access it in the view. I also do not wish to make any changes to the listView binding source.
Its name isn't accessible directly in the view.
I am able to access the events but not Properties(x:Name , Visibility etc..).
You can use VisualTreeHelper class to get your UserControl .
Get each ListViewItem by calling the ListView's ContainerFromItem or ContainerFromIndex.
Create a recursive function to find the DependencyObjects that are in each ListViewItem as a UserControl.
I made a simple to show how it works. You can refer to the following code.
MainPage.xaml
<Grid>
<ListView x:Name="MyListView" Margin="0,0,0,109">
<ListView.ItemTemplate>
<DataTemplate x:DataType="x:String">
<Grid>
<local:MyUserControl1></local:MyUserControl1>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Content="Button" Margin="682,943,0,0" VerticalAlignment="Top" Click="Button_Click"/>
</Grid>
MainPage.cs
public List<string> ItemsSourceList { get; set; }
public MainPage()
{
this.InitializeComponent();
ItemsSourceList = new List<string>();
ItemsSourceList.Add("1");
ItemsSourceList.Add("2");
ItemsSourceList.Add("3");
ItemsSourceList.Add("4");
ItemsSourceList.Add("5");
MyListView.ItemsSource = ItemsSourceList;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
foreach (var strItem in ItemsSourceList)
{
// get every listview item first
ListViewItem item = MyListView.ContainerFromItem(strItem) as ListViewItem;
// the DependencyObject is the UserControl that you want to get
DependencyObject myUserControl = FindChild(item);
}
}
public DependencyObject FindChild(DependencyObject parant)
{
int count = VisualTreeHelper.GetChildrenCount(parant);
for (int i = 0; i < count; i++)
{
var MyChild = VisualTreeHelper.GetChild(parant, i);
if (MyChild is MyUserControl1)
{
//Here can get the MyUserControl1.
MyUserControl1 myUserControl = (MyUserControl1)MyChild;
myUserControl.Foreground = new SolidColorBrush(Colors.Red);
return myUserControl;
}
else
{
var res = FindChild(MyChild);
return res;
}
}
return null;
}

How to Trigger event Cancel Button on SearchBar Xamarin Form

Xamarin Form View Model can trigger the onTextChange Event for Searchbar but there is no Event handler for OnCancelButtonClicked.
What I want:
An Event should be Triggered whenever Cancel/Close Button is clicked as below.
You can get Searchbar CloseButton event in SearchBar custom render, but I think it is not useful for your goal.
I suggest you can click search icon to refresh data source. I don one sample using Searchbar and ListView, you can take a look:
[assembly: ExportRenderer(typeof(SearchBar), typeof(CustomSearchBarRenderer))]
namespace FormsSample.Droid
{
public class CustomSearchBarRenderer: SearchBarRenderer
{
public CustomSearchBarRenderer(Context context):base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
{
base.OnElementChanged(e);
if (Control != null)
{
var searchView = Control;
searchView.Iconified = true;
searchView.SetIconifiedByDefault(false);
int searchCloseButtonId = Context.Resources.GetIdentifier("android:id/search_close_btn", null, null);
// search close button icon, you can add event for closeIcon.click.
var closeIcon = searchView.FindViewById(searchCloseButtonId);
int searchViewSearchButtonId = Control.Resources.GetIdentifier("android:id/search_mag_icon", null, null);
var searchIcon = searchView.FindViewById(searchViewSearchButtonId);
searchIcon.Click += SearchIcon_Click;
}
}
private void SearchIcon_Click(object sender, EventArgs e)
{
Element.OnSearchButtonPressed();
}
}
}
<StackLayout>
<SearchBar
x:Name="searchBar"
HorizontalOptions="Fill"
Placeholder="Search fruits..."
SearchButtonPressed="OnSearchButtonPressed"
VerticalOptions="CenterAndExpand" />
<Label
HorizontalOptions="Fill"
Text="Enter a search term and press enter or click the magnifying glass to perform a search."
VerticalOptions="CenterAndExpand" />
<ListView
x:Name="searchResults"
HorizontalOptions="Fill"
VerticalOptions="CenterAndExpand" />
</StackLayout>
public partial class Page23 : ContentPage
{
public Page23()
{
InitializeComponent();
searchResults.ItemsSource = DataService.Fruits;
}
private void OnSearchButtonPressed(object sender, EventArgs e)
{
if(string.IsNullOrEmpty(searchBar.Text))
{
searchResults.ItemsSource = DataService.Fruits;
}
else
{
searchResults.ItemsSource = DataService.GetSearchResults(searchBar.Text);
}
}
}
You can click search closebutton to move text in SearchBar firstly, then click SearchButton to refresh data for listView.

Webview text field gets scrolled to top when trying to focus - Xamarin.forms iOS

I have xamarin forms iOS app contains a webview. The webview load a html page contains some text fields.The problem I am facing is whenever we click on the text field,the keyboard shows and the entire web page will scroll to top and the text field will become invisible.When we open the same page on a browser it works fine. I have used xam.plugins.forms.keyboard overlap for my other non webview pages. How can I fix this issue? I want the textview field should be there when we focus it .
I have seen this similar problem on this question. But it didn't solved my issue. Any help is appreciated.
My XAML
<ContentPage.Content>
<Grid HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<WebView x:Name="Webview"
HeightRequest="1000"
WidthRequest="1000"
IsVisible="False"
Navigating="OnNavigating"
Navigated="OnNavigated"
VerticalOptions="FillAndExpand"/>
</Grid>
</ContentPage.Content>
You can remove the plugin and implement it by yourself.
For example, you can check the source code and copy it to your project as a PageRenderer.
In the page renderer, I add a bool value to check whether you need to use this renderer or not. Here I use the ClassId to check:
bool useThisRenderer;
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
Page p = e.NewElement as Page;
if (p.ClassId == "0")
{
useThisRenderer = false;
}
else
{
useThisRenderer = true;
}
}
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
if (useThisRenderer)
{
var page = Element as ContentPage;
if (page != null)
{
var contentScrollView = page.Content as ScrollView;
if (contentScrollView != null)
return;
RegisterForKeyboardNotifications();
}
}
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
if (useThisRenderer)
{
UnregisterForKeyboardNotifications();
}
}
Then in your Xamarin.forms project, if one of your content page does not need this renderer(for example the current page you have a webview), you can set the classid = "0" to avoid this:
public MainPage()
{
InitializeComponent();
this.ClassId = "0";
}
If you need this renderer, then do nothing about this.ClassId.
I upload a sample project here and feel free to ask me any question.

Problem with Picker items scrolling in windows ToughPad

I am taking one picker like
<Picker x:Name="picker" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" ItemDisplayBinding="{Binding ItemName}"/>
My Item class is like
public class Item
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string ItemName { get; set; }
}
Now I am adding picker itemssource like
List<Item> items= new List<Item>();
items= App.DAUtil.GetDevices();
picker.ItemsSource = items;
here I am getting devices list from my local db. When ever I run the code in windows ToughPad the picker items are scrolling continuously but it is working fine when I run the code in Local Machine.Please help me for how to stop continuous scrolling of picker.
Problem with Picker items scrolling in windows ToughPad
The matched native control is ComboBox in uwp platform, and loop scroll is by design in touch mode. If you want to tun it off you could refer this case reply then custom Picker renderer.
[assembly: ExportRenderer(typeof(Picker), typeof(CustomPickerRenderer))]
namespace App35.UWP
{
public class CustomPickerRenderer : PickerRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
if(Control != null)
{
Control.ItemsPanel = App.Current.Resources["CustomPanelTemplate"] as ItemsPanelTemplate;
}
}
}
}
Application.Resources
<ResourceDictionary>
<ItemsPanelTemplate x:Key="CustomPanelTemplate">
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ResourceDictionary>

Saving the state of multiple checkboxes for wp7

I created a button to create multiple checkbox on no. of clicks for wp7. Below the codes I used for it.
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBox x:Name="txtNewTask" HorizontalAlignment="Left" Height="72" TextWrapping="Wrap" VerticalAlignment="Top" Width="328"/>
<Button x:Name="btnAdd" Content="add" HorizontalAlignment="Left" Margin="328,0,0,0" VerticalAlignment="Top" Width="123" Click="btnAdd_Click"/>
<ListBox x:Name="lbToDoList" Margin="0,72,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Click="CheckBox_Click" Background="{x:Null}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" Name="tbkTextName" VerticalAlignment="Center" Margin="5,0,5,0" />
</StackPanel>
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Now when I exit and re-open my app, I noticed the checkbox’s are unchecked (default state) and its state is not saved. Can you please help me to save the multiple checkbox's value or state?
Can anybody help me to save the multiple checkbox's state. Thanks in advance for your help!
You need to save data to a time when your application is not running. For that staff I use IsolatedStorage. You can save anything, what you need. I found great tutorial, how it implement. hope it's help.
I Think the best way is, to save the value of the checkbox instantly when it changes.
To do so you can do the following:
Assume that the check box in the myPage.xaml looks like:
<CheckBox Content="{Binding Title}" Name="myAutoSavingCheckBox" Click="myAutoSavingCheckBox_Click"/>
In the myPage.xaml.cs you have to define the following method:
private void myAutoSavingCheckBox_Click(object sender, RoutedEventArgs e)
{
App.ViewModel.MyProperty = myAutoSavingCheckBox.IsChecked;
}
The App.ViewModel is declared in the App.xaml.cs:
public partial class App : Application
{
...
public static MainViewModel ViewModel
{
get
{
// Erstellung des Ansichtsmodells verzögern bis erforderlich
if (viewModel == null)
viewModel = new MainViewModel();
return viewModel;
}
}
...
}
Now you define your Property and the saving Function in the MainViewModel.cs as follows:
public class MainViewModel
{
private bool? myProperty;
public bool? MyProperty
{
get
{
return myProperty;
}
set
{
if (value != myProperty)
{
myProperty = value;
SaveSetting("MyProperty", myProperty);
}
}
}
public void SaveSettings(string whatShallBeSavedKey, object whatShallBeSavedValue)
{
if (IsolatedStorageSettings.ApplicationSettings.Contains("whatShallBeSavedKey"))
IsolatedStorageSettings.ApplicationSettings["whatShallBeSavedKey"] = whatShallBeSavedValue;
else
IsolatedStorageSettings.ApplicationSettings.Add("whatShallBeSavedKey", whatShallBeSavedValue);
}
}
Use IsolatedStorage.ApplicationSettings
Here are two helper methods for accessing application settings
/// Get the current value of the setting, or if it is not found, set the
/// setting to the default setting.
protected valueType GetValueOrDefault<valueType>(string Key, valueType defaultValue)
{
valueType value;
object storedValue = null;
try
{
if (_isolatedStore.TryGetValue(Key, out storedValue))
{
value = (valueType)(_isolatedStore[Key] ?? defaultValue);
}
else
{
//the key was not found
value = defaultValue;
}
}
catch (Exception ex)
{
value = defaultValue;
Logger.Error(ex, "Exception while getting IsolatedStorageSettings: ");
}
return value;
}
protected bool AddOrUpdateValue(string Key, Object value)
{
bool valueChanged = false;
object storedValue = null;
try
{
if (_isolatedStore.TryGetValue(Key, out storedValue))
{
if (storedValue != value)
{
_isolatedStore[Key] = value;
valueChanged = true;
}
}
else
{
//the key was not found
_isolatedStore.Add(Key, value);
}
}
catch (Exception ex)
{
Logger.Error(ex, "Exception while adding IsolatedStorageSettings.");
}
return valueChanged;
}
And you can then create a property on some settings class or view model that is backed by IsolatedStorage like this.
string CheckBoxValueKeyName = "checkbox_value";
bool CheckBoxValueDefault = false;
public bool CheckBoxValue
{
get
{
return GetValueOrDefault<bool>(CheckBoxValueKeyName, CheckBoxValueDefault );
}
set
{
AddOrUpdateValue(CheckBoxValueKeyName, value);
}
}
If you don't want to apply the changes of checking the box immediately to isolated storage, the WP7 Tombstone Helper is a quick way to persist the state of your controls after the app tombstones. So, yes, for persistent storage after the application is closed use Isolated Storage.

Resources