It is necessary to make the support of Right to Left style (both text and layout-s). I understand that when you set parent Grid's properties FlowDirection = "RightToLeft" in all child controls it inherited.
The question is - is there any default setting, which will shift all we need in app? Or should I set every parent greeds FlowDirection by some king of flag and set this flag as FlowDirection = "RightToLeft" if we, for example in in Arab countries?
If you are going to support any right to left language will need to have a right to left layout too. You don't need to change FlowDirection property of all of the elements since it is inherited by child elements.
MSDN:
An object inherits the FlowDirection value from its parent in the
object tree. Any element can override the value it gets from its
parent. If not specified, the default FlowDirection is LeftToRight
So usually you need to set the property once for root element/frame of the Window.
However, some elements like FontIcon and Image does not mirror automatically. FontIcon has a MirroredWhenRightToLeft property:
You can set the MirroredWhenRightToLeft property to have the glyph
appear mirrored when the FlowDirection is RightToLeft. You typically
use this property when a FontIcon is used to display an icon as part
of a control template and the icon needs to be mirrored along with the
rest of the control
For Image, you need to flip the image by transforms.
Edit:
You can set the property in the Application class where you create the main frame/page:
// Part of the App.xaml.cs in default UWP project template:
protected override void OnLaunched(LaunchActivatedEventArgs e) {
#if DEBUG
if (System.Diagnostics.Debugger.IsAttached) {
this.DebugSettings.EnableFrameRateCounter = true;
}
#endif
Frame rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null) {
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) {
//TODO: Load state from previously suspended application
}
//**********************
// Set flow direction
// *********************
if (System.Globalization.CultureInfo.CurrentCulture.TextInfo.IsRightToLeft) {
rootFrame.FlowDirection = FlowDirection.RightToLeft;
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
...
...
If you don't want to use code behind (I think its OK to use it for this scenario), you can implement IValueConverter (Not recommended):
public class RightToLeftConverter : IValueConverter {
public object Convert(object value, Type targetType,
object parameter, string language) {
if (System.Globalization.CultureInfo.CurrentCulture.TextInfo.IsRightToLeft) {
return FlowDirection.RightToLeft;
}
return FlowDirection.LeftToRight;
}
public object ConvertBack(object value, Type targetType,
object parameter, string language)
{
throw new NotImplementedException();
}
}
and use it in XAML:
<Page
...
...
FlowDirection="{Binding Converter={StaticResource RightToLeftConverter}}">
Related
I'm working on an app that uses a MapView instance called map. At a certain point I want to know if the map has been touched. To that purpose Android Studio generated this boolean return callback method (see below) for the OnTouchListener.
MapView map;
map = findViewById(R.id.view_map);
map.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch (View v) {
return false;
}
});
As you can see, unlike in a simple OnClickListener, you are apparently not free to write the method that should follow a touch event. That method appears to be fixed at return false. You cannot change it to e.g. a void method.
What is the purpose of that return? To where/what will false be returned? Is it perhaps stored in the object map, as a field of the MapView class? If I knew, I could initialize that field/variable to true, wait for the OnTouchListener to change it to false, and then use that information elsewhere in the app (e.g. to suspend the app's instruction to continuously center the map on the current GPS position).
I want to learn how to manage the state of a page between navigation.
for example a navigate onto page1 and then i navigate to page2, but when i navigate back to page1, the UI elements must already be there with the same data as before and they must not be re-initialized or data must not be binded again by the compiler.
Also what I can do to manage state of whole application such that, I terminate the app and then when i launch it next time, the same state is already there as last time. can i apply it on whole application? or what if I only want to apply it on a few pages? any help would be appreciated thanks.
or example a navigate onto page1 and then i navigate to page2, but when i navigate back to page1, the UI elements must already be there with the same data as before and they must not be re-initialized or data must not be binded again by the compiler.
For this question, you may use UIElement.CacheMode property and Frame.CacheSize property. CacheSize property sets the number of pages in the navigation history that can be cached for the frame, and CacheMode property sets a value that indicates that rendered content should be cached as a composited bitmap when possible.
As we know, an UWP app default using a rootFrame for displaying several pages, we just use Navigation method to change the content in the frame. You can see this in the OnLaunched(LaunchActivatedEventArgs e) method of a blank UWP app. But how to implement cache function? For example, your app has two page and one root frame. You can define CacheSize property in your OnLaunched(LaunchActivatedEventArgs e) method for example:
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
...
// Ensure the current window is active
rootFrame.CacheSize = 2;
Window.Current.Activate();
}
Then in your two pages's constructed functions enable CacheMode property for example:
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Enabled;
}
Also what I can do to manage state of whole application such that, I terminate the app and then when i launch it next time, the same state is already there as last time. can i apply it on whole application?
For this question, you will need to save the page state in the OnSuspending(object sender, SuspendingEventArgs e) method using Frame.GetNavigationState method, and you can save this state into the app's local settings. For example:
private void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
Frame rootFrame = Window.Current.Content as Frame;
string navstate = rootFrame.GetNavigationState();
var localSettings = ApplicationData.Current.LocalSettings;
localSettings.Values["nav"] = navstate;
deferral.Complete();
}
And how to retrieve this informaton? You can override your OnLaunched(LaunchActivatedEventArgs e) method, and at first you will need to judge how is your app be closed last time, by user, or by system using ApplicationExecutionState enumeration, for example like this:
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
//#if DEBUG
// if (System.Diagnostics.Debugger.IsAttached)
// {
// this.DebugSettings.EnableFrameRateCounter = true;
// }
//#endif
Frame rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
//rootFrame.Navigate(typeof(MainPage), e.Arguments);
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated ||
e.PreviousExecutionState == ApplicationExecutionState.ClosedByUser)
{
object value;
var localSettings = ApplicationData.Current.LocalSettings;
if (localSettings.Values.TryGetValue("nav", out value))
{
rootFrame.SetNavigationState(value as string);
}
else
{
rootFrame.Navigate(typeof(MainPage), e.Arguments);
}
}
else
{
rootFrame.Navigate(typeof(MainPage), e.Arguments);
}
}
// Ensure the current window is active
rootFrame.CacheSize = 2;
Window.Current.Activate();
}
But be aware that when an app is closed, next time you launch this app, the UI elements will be re-initialized, this function can only navigate to the page when the last time you close your app, but the data in that page will be lost. But you can also save the data to the local settings and when you navigate to the page, set the value to those UI elements.
I have an GridItem that has a fixed Height/Width.
It contains a textblock that has the max line set.
How can I determine if this text is trimmed?
I want to add special functionality if it is trimmed.
Old Way - when TextWrapping is set to None
To know if a TextBlock is trimmed, we can subscribe to its SizeChanged event and compare its ActualWidth to the MaxWidth you specified. To get the right ActualWidth of the TextBlock, we will need to leave the TextTrimming to its default value (i.e. TextTrimming.None), and set it to trimmed once the width goes over.
New Way - when TextWrapping is set to Wrap
Now that I know because the TextWrapping is set to Wrap and assume the VirticalAlignment is not specified (default to Stretch), the Width will always stay the same. We only need to monitor the SizeChanged event when the actual height of the TextBlock exceeds the height of its parent.
Let's use a Behavior to encapsulate all the logic above. What needs to be mentioned here is that a static helper class with a bunch of attached properties or a new control that inherits from TextBlock can do exactly the same thing; but being a big Blend fan, I prefer to use Behaviors whenever possible.
The Behavior
public class TextBlockAutoTrimBehavior : DependencyObject, IBehavior
{
public bool IsTrimmed
{
get { return (bool)GetValue(IsTrimmedProperty); }
set { SetValue(IsTrimmedProperty, value); }
}
public static readonly DependencyProperty IsTrimmedProperty =
DependencyProperty.Register("IsTrimmed", typeof(bool), typeof(TextBlockAutoTrimBehavior), new PropertyMetadata(false));
public DependencyObject AssociatedObject { get; set; }
public void Attach(DependencyObject associatedObject)
{
this.AssociatedObject = associatedObject;
var textBlock = (TextBlock)this.AssociatedObject;
// subscribe to the SizeChanged event so we will know when the Width of the TextBlock goes over the MaxWidth
textBlock.SizeChanged += TextBlock_SizeChanged;
}
private void TextBlock_SizeChanged(object sender, SizeChangedEventArgs e)
{
// ignore the first time height change
if (e.PreviousSize.Height != 0)
{
var textBlock = (TextBlock)sender;
// notify the IsTrimmed dp so your viewmodel property will be notified via data binding
this.IsTrimmed = true;
// unsubscribe the event as we don't need it anymore
textBlock.SizeChanged -= TextBlock_SizeChanged;
// then we trim the TextBlock
textBlock.TextTrimming = TextTrimming.WordEllipsis;
}
}
public void Detach()
{
var textBlock = (TextBlock)this.AssociatedObject;
textBlock.SizeChanged += TextBlock_SizeChanged;
}
}
The XAML
<Grid HorizontalAlignment="Center" Height="73" VerticalAlignment="Center" Width="200" Background="#FFD2A6A6" Margin="628,329,538,366">
<TextBlock x:Name="MyTextBlock" TextWrapping="Wrap" Text="test" FontSize="29.333">
<Interactivity:Interaction.Behaviors>
<local:TextBlockAutoTrimBehavior IsTrimmed="{Binding IsTrimmedInVm}" />
</Interactivity:Interaction.Behaviors>
</TextBlock>
</Grid>
Note that the Behavior exposes a dependency property IsTrimmed, you can data bind it to a property in your viewmodel (i.e. IsTrimmedInVm in this case).
P.S. There's no FormattedText function in WinRT otherwise the implementation could be a little bit different.
We ended up making a static function
// Ensure block does not have MAXLINES or text trimming set prior to checking
public static bool IsTruncated(TextBlock block, int maxLines)
{
if (block == null)
{
throw new ArgumentNullException("block");
}
//the cut-off height is the height at which text will be cut off in the UI
var cutOffHeight = maxLines * block.LineHeight;
//determine whether the actual height of the TextBlock is greater than the cut-off height
return block.ActualHeight > cutOffHeight;
}
The trick is to make sure that Maxlines and text trimming is NOT set on the Textblock prior to running this function. After this function returns, that is when the Maxlines is set. In my case I just saved the returned Boolean in a containing object so I knew it was longer. Then I set maxlines and another button to see the extended content based on that Boolean.
I have a UICollectionView with images. The user can select (multiselect) the images. When the user taps a single image, everything works fine. The SelectedBackgroundView is visible and on tap again, the normal image is visible.
But my problem is, I have a option for the user "Select all". In that i want to select all items programmatically. With following code:
for (int i = 0; i < CollectionView.NumberOfItemsInSection(0); i++)
{
var ip = NSIndexPath.FromItemSection(i, 0);
CollectionView.SelectItem(ip, false, UICollectionViewScrollPosition.None);
}
The following method returns the correct number for the selected items:
var number = CollectionView.GetIndexPathsForSelectedItems().Length;
But the UI is not changing to the SelectedBackgroundView.
Can anyone help me? Thanks.
Calling SelectItem does not cause the display to be updated; it just changes the Selected property of the UICollectionViewCell therefore updating the selected index set in the collection view.
What I do is override the Selected property of my UICollectionViewCell implementation and adjust the UI at that point:
public class MyCell : UICollectionViewCell
{
// ...
public override bool Selected
{
get { return base.Selected; }
set
{
base.Selected = value;
// change the state of the selected background
imageBackground.Image = LoadAnImage(value ? "BackgroundOn" : "BackgroundOff");
}
}
}
This way ensures that the UI is updated at all possible points when the selected state of the cell changes, either by user interaction or programmatically calling SelectItem or DeselectItem on the collection view.
I do not personally use the SelectedBackgroundView property on a cell (I do my own layering, most of the time), but you may have to manually bring that view to the front yourself in a similar Selected property override.
I'm trying to add a menu item such that it acts like a check mark where the user can check/uncheck, and the other classes can see that menu item's check mark status. I received a suggestion of creating a class for the menu option (with a popup option), however, I can't create a class for the menu option when I'm in the resource layout editor in Visual Studio 2005. It would be great to hear suggestions on the easiest way to create menu items that can do what I have described.
You should use the CCmdUI::SetCheck function to add a checkbox to a menu item, via an ON_UPDATE_COMMAND_UI handler function, and the ON_COMMAND handler to change the state of the checkbox. This method works for both for your application's main menu and for any popup menus you might create.
Assuming you have an MDI or SDI MFC application, you should first decide where you want to add the handler functions, for example in the application, main frame, document, or view class. This depends on what the flag will be used for: if it controls application-wide behaviour, put it in the application class; if it controls view-specific behaviour, put it in your view class, etc.
(Also, I'd recommend leaving the menu item's Checked property in the resource editor set to False.)
Here's an example using a view class to control the checkbox state of the ID_MY_COMMAND menu item:
// MyView.h
class CMyView : public CView
{
private:
BOOL m_Flag;
afx_msg void OnMyCommand();
afx_msg void OnUpdateMyCommand(CCmdUI* pCmdUI);
DECLARE_MESSAGE_MAP()
};
// MyView.cpp
BEGIN_MESSAGE_MAP(CMyView, CView)
ON_COMMAND(ID_MY_COMMAND, OnMyCommand)
ON_UPDATE_COMMAND_UI(ID_MY_COMMAND, OnUpdateMyCommand)
END_MESSAGE_MAP()
void CMyView::OnMyCommand()
{
m_Flag = !m_Flag; // Toggle the flag
// Use the new flag value.
}
void CMyView::OnUpdateMyCommand(CCmdUI* pCmdUI)
{
pCmdUI->SetCheck(m_Flag);
}
You should ensure the m_Flag member variable is initialised, for example, in the CMyView constructor or OnInitialUpdate function.
I hope this helps!
#ChrisN's approach doesn't quite work for MFC Dialog applications (the pCmdUI->SetCheck(m_Flag); has no effect). Here is a solution for Dialog apps:
// MyView.h
class CMyView : public CView
{
private:
BOOL m_Flag;
CMenu * m_menu;
virtual BOOL OnInitDialog();
afx_msg void OnMyCommand();
DECLARE_MESSAGE_MAP()
};
// MyView.cpp
BEGIN_MESSAGE_MAP(CMyView, CView)
ON_COMMAND(ID_MY_COMMAND, OnMyCommand)
END_MESSAGE_MAP()
BOOL CMyView::OnInitDialog()
{
m_menu = GetMenu();
}
void CMyView::OnMyCommand()
{
m_Flag = !m_Flag; // Toggle the flag
if (m_flag) {
m_menu->CheckMenuItem(ID_MENUITEM, MF_CHECKED | MF_BYCOMMAND);
} else {
m_menu->CheckMenuItem(ID_MENUITEM, MF_UNCHECKED | MF_BYCOMMAND);
}
}
References:
http://www.codeguru.com/forum/showthread.php?t=322261
I ended up retrieving the menu from the mainframe using GetMenu() method, and then used that menu object and ID numbers to call CheckMenuItem() with the right flags, as well as GetMenuState() function.