I'm trying to move/rotate/scale a model using the TransformManipulator3D control in UWP.
I do get it to work but the camera does not stop moving when I'm manipulating the model. So when I try to move/rotate/scale the model the camera also moves and this behavior causes the actual move/scale/rotate to be very wonky and not at all smooth or what is expected.
What am I missing and how can I get this behavior to stop from happening?
Thank you.
I think you need to change your camera mouse gesture to a different mouse button.
I got it working without having to change mouse gestures for the camera.
I did the following:
private void viewer_OnMouse3DDown(object sender, MouseDown3DEventArgs e)
{
if(e.HitTestResult != null && e.HitTestResult.ModelHit is MeshGeometryModel3D model && GroupModel.Any(x => x == model))
{
if(ViewerContext.Selected == model)
{
ViewerContext.Selected.PostEffects = null;
ViewerContext.Selected = null;
return;
}
if(ViewerContext.Selected != null)
{
ViewerContext.Selected.PostEffects = null;
}
ViewerContext.Selected = model;
ViewerContext.Selected.PostEffects = string.IsNullOrEmpty(ViewerContext.Selected.PostEffects) ? "border[color:#00FFDE]" : null;
return;
}
if (e.HitTestResult != null && e.HitTestResult.ModelHit is MeshGeometryModel3D pointer && !GroupModel.Any(x => x == pointer))
{
ViewerContext.IsRotationEnabled = false;
ViewerContext.IsMoveEnabled = false;
ViewerContext.IsPanEnabled = false;
return;
}
}
and
private void viewer_OnMouse3DUp(object sender, MouseUp3DEventArgs e)
{
ViewerContext.IsRotationEnabled = true;
ViewerContext.IsMoveEnabled = true;
ViewerContext.IsPanEnabled = true;
}
The pointer variable checks if the ModelHit is part of the TransformManipulator3D control.
I followed the UWP sample for the PostEffects.
The ViewerContext is the ViewModel holding the Viewport3DX properties to know when the camera can again rotate, move or pan.
The GroupModel holds all the models as MeshGeometryModel3D objects.
The TransformManipulator3D control binds to the Selected property on ViewerContext which is also of type MeshGeometryModel3D.
Related
My NowPlayFullPage has a PlaylistControl, which is basically a ListView.
<local:PlaylistControl
x:Name="FullPlaylistControl"
Margin="10,10,10,0"
AllowReorder="True"
AlternatingRowColor="False"
Background="Transparent"
IsNowPlaying="True"
RequestedTheme="Dark" />
The ItemTemplate of the PlaylistControl is the following:
<local:PlaylistControlItem
Data="{x:Bind}"
DataContext="{x:Bind}"
RequestedTheme="{Binding ElementName=PlaylistController, Path=RequestedTheme}"
ShowAlbumText="{Binding ElementName=PlaylistController, Path=ShowAlbumText}" />
And in the Loaded event of the PlaylistControlItem, I called a function SetTextColor
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
MediaHelper.SwitchMusicListeners.Add(this);
SetTextColor(MediaHelper.CurrentMusic);
}
public void SetTextColor(Music music)
{
if (Data == music)
{
TitleTextBlock.Foreground = ArtistTextButton.Foreground = AlbumTextButton.Foreground = DurationTextBlock.Foreground =
LongArtistTextButton.Foreground = LongArtistAlbumPanelDot.Foreground = LongAlbumTextButton.Foreground = ColorHelper.HighlightBrush;
TextColorChanged = true;
}
else if (TextColorChanged)
{
if (RequestedTheme == ElementTheme.Dark)
{
TitleTextBlock.Foreground = ColorHelper.WhiteBrush;
ArtistTextButton.Foreground = AlbumTextButton.Foreground = DurationTextBlock.Foreground =
LongArtistTextButton.Foreground = LongArtistAlbumPanelDot.Foreground = LongAlbumTextButton.Foreground = ColorHelper.GrayBrush;
}
else
{
TitleTextBlock.Foreground = ArtistTextButton.Foreground = AlbumTextButton.Foreground = DurationTextBlock.Foreground =
LongArtistTextButton.Foreground = LongArtistAlbumPanelDot.Foreground = LongAlbumTextButton.Foreground = ColorHelper.BlackBrush;
}
TextColorChanged = false;
}
}
My question is, why does the RequestedTheme in the SetTextColor called in the Loaded event have the value of ElementTheme.Default instead of ElementTheme.Dark? When does the RequestTheme of PlaylistControlItem hold the value of Dark so that my text color can be set correctly?
Advisably you should he handling this using ThemeResource's in XAML, not in code, see: https://learn.microsoft.com/en-us/windows/uwp/xaml-platform/themeresource-markup-extension
But to answer your question this is expected behaviour. ElementTheme.Default simply means the element has not had it's theme overridden and is using the default app theme. The other two values mean the element has specifically had it's theme overridden. App.Current.RequestedTheme gives the application's actual theme. FrameworkElement.RequestedTheme will always have a value of Default unless you explicitly set it to something else on that specific element. All of it's children will still have the value Default.
Note, you should compare against ActualTheme, not RequestedTheme, as a parent may have caused it to be using a different theme than the application if it's value is still ElementTheme.Default.
A method like below might help you to get a proper value of Light/Dark.
public static ElementTheme GetEffectiveTheme(FrameworkElement e)
{
if (e.ActualTheme == ElementTheme.Default)
return App.Current.RequestedTheme == ApplicationTheme.Dark ? ElementTheme.Dark : ElementTheme.Light;
return e.ActualTheme;
}
But also, just use ThemeResources. They automatically re-evaluate on Theme change, no need for any code or event listeners.
So i have a script that creates buttons, and a script that makes these buttons interactable on certain scenarios.
Problem is, in the script that creates the buttons, 2 of the buttons it creates have more child buttons underneath them. With my following code i can easily make those childbuttons interactable whenever i want, but it wont recognize the parents. I realize why (because my list checks for childs) but I have no clue on how to fix this. Make a second list for the parent buttons or? Code is below.
MenuButton[] MenuButtons = _selectionEditMenuPanel.GetComponentsInChildren<MenuButton>(true);
for (int i = 0; i < MenuButtons.Length; i++)
{
if (MenuButtons[i].name == "edit_group" || MenuButtons[i].name == "edit_ungroup")
{
if (_selection.SelectedPageObject.IsGroup())
{
MenuButtons[i].GetComponent<MenuButton>().menuButton.GetComponent<TestButton>().Interactable = true;
if (!((PageObjectGroup)_selection.SelectedPageObject).IsTempGroup)
{
MenuButtons[i].title.text = TranslationSystem.Request("edit_ungroup");
MenuButtons[i].name = "edit_ungroup";
}
else
{
MenuButtons[i].title.text = TranslationSystem.Request("edit_group");
MenuButtons[i].name = "edit_group";
}
}
else
{
MenuButtons[i].title.text = TranslationSystem.Request("edit_group");
MenuButtons[i].name = "edit_group";
MenuButtons[i].GetComponent<MenuButton>().menuButton.GetComponent<testButton>().Interactable = false;
}
}
if (MenuButtons[i].name == "edit_crop")
{
//Only make crop button interactive when pageobject bitmap is selected
MenuButtons[i].GetComponent<MenuButton>().menuButton.GetComponent<testButton>().Interactable = _selection.SelectedPageObject is PageObjectBitmap;
}
//TODO Make this work with edit align? It works with other buttons.
if (MenuButtons[i].name == "edit_align")
{
if (!_selection.SelectedPageObject.IsGroup())
{
MenuButtons[i].GetComponent<MenuButton>().menuButton.GetComponent<testButton>().Interactable = false;
}
else
{
MenuButtons[i].GetComponent<MenuButton>().menuButton.GetComponent<testButton>().Interactable = true;
}
}
It works for everything except the last check, edit_align(this is a button with childs underneath it) I'll post the general setup of the button creating script below, but NOTE: I cant edit that scripts, it's not mine so please don't advise me to edit that.
private static MenuItem _selectionEditMenu = new MenuItem(Resources.Load<Sprite>("Edit_128"))
{ new MenuItem(Resources.Load<Sprite>("Sprites/Icons/Align_Left_1_128"), "edit_align", true, true, null)
{
new MenuItem(Resources.Load<Sprite>("Sprites/Icons/Distribute_Horizontally_128"), "edit_align_distribute_evenly"
new MenuItem(Resources.Load<Sprite>("Sprites/Icons/Uniform_Height_128"), "edit_align_uniform_height"
I can reach the edit_align_Distribute_evenly & the Uniform height, but not the parent above called: edit_align.
NOTE: I left away some syntax etc cause of company names in there. So don't worry about syntax not being correct.
Thanks, every help is highly appreciated.
I have a problem with refreshing Oxyplot graph in Xamarin Android. I'm using Model.InvalidatePlot(true) but still doesnt work.
In my ViewModel I have property PlotModel and method for Refresh like code below. GroupSales is my MvxObservableCollection of GroupSale.
public void RefreshTest()
{
GroupSales.Clear();
var groupSales = DemoData.GetGroupSaleList(_shop.Id);
groupSales.Add(new GroupSale()
{
Name = "Test",
Sum = 5555,
Color = Constants.DefaultColor
});
foreach (var item in groupSales)
{
GroupSales.Add(item);
}
Model = OxyPlotModelCreator.GetGroupSalesModel(GroupSales);
Model.InvalidatePlot(true);
}
private PlotModel _model;
public PlotModel Model
{
get { return _model; }
set
{
_model = value;
RaisePropertyChanged(() => Model);
}
}
After call method RefreshTest my MvxObservableCollection is updated and Model too but still looking same in view. Only when Im change mobile orientation its update (cuz Im using two views for portrait and landscape so its initialized again) but I need refresh PlotModel after click on Refresh button.
I tried already call this method in Android fragment and Invalidete PlotView and Model like this:
Button button = _view.FindViewById<Button>(Resource.Id.refreshButton);
button.Click += delegate
{
ViewModel.RefreshTest();
if (plotView != null && ViewModel.Model != null)
{
plotView.InvalidatePlot(true);
plotView.Invalidate();
plotView.RefreshDrawableState();
plotView.Model.InvalidatePlot(true);
}
};
But still doesnt work.... Can someone help me?
EDIT
I Initialize Model in Fragment like this:
var plotView = _view.FindViewById<PlotView>(Resource.Id.groupSalesModel);
if (plotView != null && ViewModel.Model != null)
{
plotView.Model = ViewModel.Model;
}
Oh I got it... I just bind in fragment like this:
var bindset = this.CreateBindingSet<GroupSalesFragment, GroupSalesViewModel>();
bindset.Bind(plotView).For(c => c.Model).To(vm => vm.Model);
bindset.Apply();
And its working now....
I have been working on this issue for a month now but can't seem to solve it. I am trying to drag an item from RadListView1 to RadListView2. I don't actually want to move or copy this item to RadListView2. I want to combine the item with an item that I am over when I release the mouse button over RadListView2 and display it in a RadListView3. Example. Drag a song name over to a singer and it combine the singer and songname into the RadListView3.
I just can't figure out the drag events and how to get the item I dragged to in RadListView2. Hopefully I didn't confuse the heck out of you.
Any help appreciated. I've looked at the Telerik docs forever but can't get it.
Thanks.
I can't even get this to work
private void DragDropService_PreviewDragOver(object sender, RadDragOverEventArgs e)
{
e.CanDrop = e.HitTarget is DetailListViewDataCellElement || e.HitTarget is DetailListViewElement;
Debug.WriteLine("PreviewDragOver triggered");
}
private void DragDropService_PreviewDragDrop(object sender, RadDropEventArgs e)
{
BaseListViewVisualItem draggedItem = e.DragInstance as BaseListViewVisualItem;
DetailListViewDataCellElement cellElement = e.HitTarget as DetailListViewDataCellElement;
DetailListViewElement viewElement = e.HitTarget as DetailListViewElement;
if (cellElement == null && viewElement == null)
{
Debug.WriteLine("All NULL...returning");
return;
}
e.Handled = true;
if (viewElement != null) Debug.WriteLine("Over ViewElement");
if (cellElement != null) Debug.WriteLine("Over cellElement");
}
See this article, in the PreviewDragDrop event, you have the DragInstance and the HitTarget.
I am developing a WPF for touch enabled device. I am facing a strange problem. My XAML structure is
<ScrollViewer>
<StackPanel orientation="Horizontal">
<!-- Control goes here -->
</StackPanel>
<ScrollViewer>
Now
To enable scrolling on touch I have to set PannigMode to HorizontalOnly
To receive manipulation events I have to set PannigMode to None
Problem is I have to have these two functionality simultaneously.
Is there any work around so that the scrollviewer is scrolled on touch and also the manipulationcompleted event fires.
Please help.
I had the same issue. You have at least two options
use MS Surface Toolkit
fix ScrollViewer
I've chosen the second one. Simply create a custom control, inherit from ScrollViewer, in Generic.xaml you only need to put a <ContentPresenter />, nothing more.
The real job is in the code behind, but also not so complecated. I had to check whether the user touched a button or just wanted to scroll. The trick is to check what is on the touch points and turn on / off the panning mode.
And here is the code:
namespace Demo.Controls
{
public class ScrollViewerWithTouch : ScrollViewer
{
private PanningMode panningMode;
private bool panningModeSet;
static ScrollViewerWithTouch()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ScrollViewerWithTouch), new FrameworkPropertyMetadata(typeof(ScrollViewerWithTouch)));
}
protected override void OnManipulationCompleted(ManipulationCompletedEventArgs e)
{
base.OnManipulationCompleted(e);
// set it back
this.PanningMode = this.panningMode;
}
protected override void OnManipulationStarted(ManipulationStartedEventArgs e)
{
// figure out what has the user touched
var result = VisualTreeHelper.HitTest(this, e.ManipulationOrigin);
if (result != null && result.VisualHit != null)
{
var hasButtonParent = this.HasButtonParent(result.VisualHit);
// if user touched a button then turn off panning mode, let style bubble down, in other case let it scroll
this.PanningMode = hasButtonParent ? PanningMode.None : this.panningMode;
}
base.OnManipulationStarted(e);
}
protected override void OnTouchDown(TouchEventArgs e)
{
// store panning mode or set it back to it's original state. OnManipulationCompleted does not do it every time, so we need to set it once more.
if (this.panningModeSet == false)
{
this.panningMode = this.PanningMode;
this.panningModeSet = true;
}
else
{
this.PanningMode = this.panningMode;
}
base.OnTouchDown(e);
}
private bool HasButtonParent(DependencyObject obj)
{
var parent = VisualTreeHelper.GetParent(obj);
if ((parent != null) && (parent is ButtonBase) == false)
{
return HasButtonParent(parent);
}
return parent != null;
}
}
}