View.findNavController() vs Fragment.findNavController() - android-architecture-components

Anywhere in a NavHostFragment I can do findNavController().navigateUp()
Or, if in my Fragment I have a button to be used for navigation, I could do either:
editButton.setOnClickListener { v ->
v.findNavController().navigateUp()
}
or
editButton.setOnClickListener {
findNavController().navigateUp()
}
Why would I use one extension function vs the other when setting up a button click listener in a Fragment?

They are almost the same, Fragment.findNavController() is just a handy shortcut, it actually calls Navigation.findNavController(view) at the end. Both of them are getting the NavController from the root view of the fragment.
// NavHostFragment.java
public static NavController findNavController(#NonNull Fragment fragment) {
....
View view = fragment.getView();
if (view != null) {
return Navigation.findNavController(view);
}
...
}

Thank you for the Java answer, I offer a ViewBinding solution in kotlin, doing the same
// NavHostFragment.kotlin
fun findMyNavController(#NonNull fragment: Fragment): NavController {
return Navigation.findNavController(binding.root)
}

Although they are not identical as suggested by the top voted answer, the performance difference should be negligible in general scenarios. However if you use the v.findNavController() on a View which is deeply nested down, then you should prefer Fragment extension findNavController() as it will perform better.
In general I don't see any reason to prefer the v.findNavController over the Fragment extension. following is the complete code of this method from NavHostFragment and it only calls Navigation.findNavController if it doesn't find the NavController using the fragment
public static NavController findNavController(#NonNull Fragment fragment) {
Fragment findFragment = fragment;
while (findFragment != null) {
if (findFragment instanceof NavHostFragment) {
return ((NavHostFragment) findFragment).getNavController();
}
Fragment primaryNavFragment = findFragment.requireFragmentManager()
.getPrimaryNavigationFragment();
if (primaryNavFragment instanceof NavHostFragment) {
return ((NavHostFragment) primaryNavFragment).getNavController();
}
findFragment = findFragment.getParentFragment();
}
// Try looking for one associated with the view instead, if applicable
View view = fragment.getView();
if (view != null) {
return Navigation.findNavController(view);
}
throw new IllegalStateException("Fragment " + fragment
+ " does not have a NavController set");
}

Related

TornadoFX Drag and Drop on a TreeView

I am new to JavaFX and, therefore, also to TornadoFX so please bear with me.
I have a simple app in Java but want to move it to Kotlin and am running into problems finding the corresponding mechanisms in TornadoFX. I have a ListView holding implementations of IStoryItem representing Stories and Chapters. I want to be able to move the chapters around and even from one story to another. The TreeView in Java has the following implementation in its setCellFactory call:
tv.setCellFactory(new Callback<TreeView<IStoryItem>, TreeCell<IStoryItem>>() {
#Override
public TreeCell<IStoryItem> call(TreeView<IStoryItem> siTreeView) {
TreeCell<IStoryItem> cell = new TreeCellStoryEditor();
cell.setOnDragDetected((MouseEvent event) -> {
// Don't drag Story nodes.
if (cell.getItem() instanceof Story) return;
Dragboard db = cell.startDragAndDrop(TransferMode.MOVE);
// Put the Part on the dragboard
// From: https://stackoverflow.com/a/30916660/780350
ClipboardContent content = new ClipboardContent();
content.put(objectDataFormat, cell.getItem());
db.setContent(content);
event.consume();
});
cell.setOnDragOver((DragEvent event) -> {
if (event.getGestureSource() != cell && event.getDragboard().hasContent(objectDataFormat)) {
/* allow for moving */
event.acceptTransferModes(TransferMode.MOVE);
}
event.consume();
});
cell.setOnDragEntered((DragEvent event) -> {
IStoryItem item = cell.getItem();
if (item instanceof Story &&
event.getGestureSource() != cell &&
event.getDragboard().hasContent(objectDataFormat)) {
cell.setUnderline(true);
}
event.consume();
});
cell.setOnDragExited((DragEvent event) -> {
cell.setUnderline(false);
event.consume();
});
cell.setOnDragDropped((DragEvent event) -> {
try {
Dragboard db = event.getDragboard();
boolean success = false;
if (db.hasContent(objectDataFormat)) {
Part droppedPart = (Part)db.getContent(objectDataFormat);
IStoryItem targetStoryItem = cell.getItem();
// Question: How to handle drops between leaf items or
// before the initial leaf or after the final leaf.
if (targetStoryItem instanceof Story) {
Story story = (Story) targetStoryItem;
updateStoryWith(droppedPart, story);
addPartTo(cell.getTreeItem(), droppedPart);
success = true;
}
}
event.setDropCompleted(success);
event.consume();
} catch (Exception e) {
System.out.println(e.getMessage());
}
});
cell.setOnDragDone((DragEvent event) -> {
if (event.getTransferMode() == TransferMode.MOVE) {
IStoryItem item = cell.getItem();
TreeItem<IStoryItem> ti = cell.getTreeItem();
TreeItem<IStoryItem> pti = ti.getParent();
pti.getChildren().remove(ti);
IStoryItem psi = pti.getValue();
// Remove the Part/Chapter from its previous Story
boolean removed = removePartFrom(psi, item);
}
event.consume();
});
cell.setEditable(true);
return cell;
};
});
I have looked for something similar in TornadoFX but can't find anything that looks like it would work. I am already using the cellFormat builder but I can't figure out how to add the event handlers inside it. I see from IntelliJ's intellisense that there is also a cellFactory builder but I am not sure how to make use of it or how to add the event handlers to it.
You can use the exact same technique in TornadoFX. Remember, TornadoFX just applies a high level API on top of JavaFX. You can always still access the underlying JavaFX API's without issue.
tv.setCellFactory {
object : TreeCell<IStoryItem>() {
init {
setOnDragOver { event ->
}
setOnDragEntered { event ->
}
setOnDragExited { event ->
}
setOnDragDropped { event ->
}
}
}
}

Moving comparisons out from the Update method: using delegates instead or another approach?

Let's go straight to an example. Let's say we have:
Update(){
if (value.Equals("circular")) moveGameObjectInACircularWay();
else if (value.Equals("linear")) moveGameObjectInALinearWay();
}
I think that is not very elegant solution. Unity needs to perform a comparison every frame. That does not sound very optimal to me. I'm just guessing it should be some other way to implement the same like:
Start () {
if (value.Equals("circular")) movement += moveGameObjectInACircularWay;
else if (value.Equals("linear")) movement += moveGameObjectInALinearWay;
}
Update () {
movement();
}
I guess the solution is related with delegates. That's why my proposed solution looks like delegates. I don't understand what delegates are well yet.
From MSDN "A delegate in C# is similar to a function pointer in C or C++. Using a delegate allows the programmer to encapsulate a reference to a method inside a delegate object." (https://msdn.microsoft.com/en-us/library/aa288459(v=vs.71).aspx) In short is a pointer to a method. What you want to do is the following:
using UnityEngine;
using System.Collections;
public delegate void MovementDelegate();
public class Movement : MonoBehaviour {
MovementDelegate movementFunction=null;
public string value = "linear";
void Start () {
if (value.Equals("circular")) movementFunction = moveGameObjectInACircularWay;
else if (value.Equals("linear")) movementFunction = moveGameObjectInALinearWay;
}
// Update is called once per frame
void Update()
{
if (movementFunction != null)
{
movementFunction();
}
}
void moveGameObjectInACircularWay()
{
Debug.Log("do circular movement here");
}
void moveGameObjectInALinearWay()
{
Debug.Log("do linear movement here");
}
}
The functions you declare must have the same signature as the delegate signature. If you want to add parameters to it, ex. an int, decalre your delegate as
public delegate void MovementDelegate(int speed);
and your implementation functions as
void moveGameObjectInACircularWay(int speed)
void moveGameObjectInALinearWay(int speed)
and change the call to
movementFunction(yourIntHere)
UPDATED!: Thanks to Joe Blow suggestion here is another solution:
public class Movement : MonoBehaviour
{
Action<int> movementFunction = null;
public string value = "linear";
void Start()
{
if (value.Equals("circular")) movementFunction = moveGameObjectInACircularWay;
else if (value.Equals("linear")) movementFunction = moveGameObjectInALinearWay;
}
// Update is called once per frame
void Update()
{
if (movementFunction != null)
{
movementFunction(2);
}
}
void moveGameObjectInACircularWay(int speed)
{
Debug.Log("do circular movement here "+ speed);
}
void moveGameObjectInALinearWay(int speed)
{
Debug.Log("do linear movement here " + speed);
}
}
My favorite answer has been written by Joe Blow in the comments:
Unity is components based. We better switch to Component-Based Thinking instead working with delegates.
So make two (or more) different scripts, and put those on the game object in question. Then, turn on and off these components as you wish.
So we would have to scripts added to our game object: MoveGameObjectInACircularWay.cs and MoveGameObjectInALinearWay.cs. Then a MainGameObjectScript.cs also added to our game object with the following code:
void Start () {
GetComponent()<MoveGameObjectInACircularWay>.active = true;
GetComponent()<MoveGameObjectInALinearWay>.active = false;
}

Determining object types in Qt

I have a series of QTextEdits and QLineEdits connected to a slot through a QSignalMapper(which emits a textChanged(QWidget*) signal). When the connected slot is called (pasted below), I need to be able to differentiate between the two so I know whether to call the text() or toPlainText() function. What's the easiest way to determine the subclass type of a QWidget?
void MainWindow::changed(QWidget *sender)
{
QTextEdit *temp = qobject_cast<QTextEdit *>(sender);
QString currentText = temp->toPlainText(); // or temp->text() if its
// a QLineEdit...
if(currentText.compare(""))
{
...
}
else
{
...
}
}
I was considering using try-catch but Qt doesn't seem to have very extensive support for Exceptions... Any ideas?
Actually, your solution is already almost there. In fact, qobject_cast will return NULL if it can't perform the cast. So try it on one of the classes, if it's NULL, try it on the other:
QString text;
QTextEdit *textEdit = qobject_cast<QTextEdit*>(sender);
QLineEdit *lineEdit = qobject_cast<QLineEdit*>(sender);
if (textEdit) {
text = textEdit->toPlainText();
} else if (lineEdit) {
text = lineEdit->text();
} else {
// Return an error
}
You can also use sender->metaObject()->className() so you won't make unnecesary casts. Specially if you have a lot of classes to test. The code will be like this:
QString text;
QString senderClass = sender->metaObject()->className();
if (senderClass == "QTextEdit") {
QTextEdit *textEdit = qobject_cast<QTextEdit*>(sender);
text = textEdit->toPlainText();
} else if (senderClass == "QLineEdit") {
QLineEdit *lineEdit = qobject_cast<QLineEdit*>(sender);
text = lineEdit->text();
} else {
// Return an error
}
I know is an old question but I leave this answer just in case it would be useful for somebody...

refactor dilemma

I want to extract the guard statement from the following method
private void CreateProxy()
{
//extract the following guard statement.
Host selected = this.comboBox1.SelectedItem as Host;
if (selected == null)
{
return;
}
this.SearchProxy = ServiceProxy.ProxyFactory.CreateSearchProxy(GetSelectedIP().ToString());
this.StreamProxy = ServiceProxy.ProxyFactory.CreatePlayerProxy(GetSelectedIP().ToString());
}
//extracted guard method
public bool IsHostSelected()
{
Host selected = this.comboBox1.SelectedItem as Host;
if (selected == null)
{
return false;
}
return true;
}
see? now i have to add return value for the extracted method, is this kinda ugly?
any better solution to avoid adding the return value for the extracted method?
I don't see the big deal. First, I would rewrite it as:
static bool SelectedItemIsHost(ComboBox box) {
return box.SelectedItem is Host;
}
Note the rename, the ComboBox as a parameter, and the body change.
Now, this makes your code read more clearly:
void CreateProxy() {
if(SelectedItemIsHost(this.comboBox1)) {
this.SearchProxy = ServiceProxy.ProxyFactory.CreateSearchProxy(GetSelectedIP().ToString());
this.StreamProxy = ServiceProxy.ProxyFactory.CreatePlayerProxy(GetSelectedIP().ToString());
}
}
So now it reads "if the selected item is a Host then do stuff."
Now, this goes way beyond your question, but this looks like a big coupling of UI logic and domain logic. You might want to reconsider a decoupling there.
any better solution to avoid adding the return value for the extracted method?
Yes:
//extracted guard method
public bool IsHostSelected()
{
Host selected = this.comboBox1.SelectedItem as Host;
return selected != null;
}

How to tell if .NET code is being run by Visual Studio designer

I am getting some errors thrown in my code when I open a Windows Forms form in Visual Studio's designer. I would like to branch in my code and perform a different initialization if the form is being opened by designer than if it is being run for real.
How can I determine at run-time if the code is being executed as part of designer opening the form?
if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
{
// Design time logic
}
To find out if you're in "design mode":
Windows Forms components (and controls) have a DesignMode property.
Windows Presentation Foundation controls should use the IsInDesignMode attached property.
The Control.DesignMode property is probably what you're looking for. It tells you if the control's parent is open in the designer.
In most cases it works great, but there are instances where it doesn't work as expected. First, it doesn't work in the controls constructor. Second, DesignMode is false for "grandchild" controls. For example, DesignMode on controls hosted in a UserControl will return false when the UserControl is hosted in a parent.
There is a pretty easy workaround. It goes something like this:
public bool HostedDesignMode
{
get
{
Control parent = Parent;
while (parent!=null)
{
if(parent.DesignMode) return true;
parent = parent.Parent;
}
return DesignMode;
}
}
I haven't tested that code, but it should work.
The most reliable approach is:
public bool isInDesignMode
{
get
{
System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess();
bool res = process.ProcessName == "devenv";
process.Dispose();
return res;
}
}
The most reliable way to do this is to ignore the DesignMode property and use your own flag that gets set on application startup.
Class:
public static class Foo
{
public static bool IsApplicationRunning { get; set; }
}
Program.cs:
[STAThread]
static void Main()
{
Foo.IsApplicationRunning = true;
// ... code goes here ...
}
Then just check the flag whever you need it.
if(Foo.IsApplicationRunning)
{
// Do runtime stuff
}
else
{
// Do design time stuff
}
I had the same problem in Visual Studio Express 2013. I tried many of the solutions suggested here but the one that worked for me was an answer to a different thread, which I will repeat here in case the link is ever broken:
protected static bool IsInDesigner
{
get { return (Assembly.GetEntryAssembly() == null); }
}
The devenv approach stopped working in VS2012 as the designer now has its own process. Here is the solution I am currently using (the 'devenv' part is left there for legacy, but without VS2010 I am not able to test that though).
private static readonly string[] _designerProcessNames = new[] { "xdesproc", "devenv" };
private static bool? _runningFromVisualStudioDesigner = null;
public static bool RunningFromVisualStudioDesigner
{
get
{
if (!_runningFromVisualStudioDesigner.HasValue)
{
using (System.Diagnostics.Process currentProcess = System.Diagnostics.Process.GetCurrentProcess())
{
_runningFromVisualStudioDesigner = _designerProcessNames.Contains(currentProcess.ProcessName.ToLower().Trim());
}
}
return _runningFromVisualStudioDesigner.Value;
}
}
/// <summary>
/// Are we in design mode?
/// </summary>
/// <returns>True if in design mode</returns>
private bool IsDesignMode() {
// Ugly hack, but it works in every version
return 0 == String.CompareOrdinal(
"devenv.exe", 0,
Application.ExecutablePath, Application.ExecutablePath.Length - 10, 10);
}
System.Diagnostics.Debugger.IsAttached
It's hack-ish, but if you're using VB.NET and when you're running from within Visual Studio My.Application.Deployment.CurrentDeployment will be Nothing, because you haven't deployed it yet. I'm not sure how to check the equivalent value in C#.
using (System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess())
{
bool inDesigner = process.ProcessName.ToLower().Trim() == "devenv";
return inDesigner;
}
I tried the above code (added a using statement) and this would fail on some occasions for me. Testing in the constructor of a usercontrol placed directly in a form with the designer loading at startup. But would work in other places.
What worked for me, in all locations is:
private bool isDesignMode()
{
bool bProcCheck = false;
using (System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess())
{
bProcCheck = process.ProcessName.ToLower().Trim() == "devenv";
}
bool bModeCheck = (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime);
return bProcCheck || DesignMode || bModeCheck;
}
Maybe a bit overkill, but it works, so is good enough for me.
The success in the example noted above is the bModeCheck, so probably the DesignMode is surplus.
You check the DesignMode property of your control:
if (!DesignMode)
{
//Do production runtime stuff
}
Note that this won't work in your constructor because the components haven't been initialized yet.
When running a project, its name is appended with ".vshost".
So, I use this:
public bool IsInDesignMode
{
get
{
Process p = Process.GetCurrentProcess();
bool result = false;
if (p.ProcessName.ToLower().Trim().IndexOf("vshost") != -1)
result = true;
p.Dispose();
return result;
}
}
It works for me.
I'm not sure if running in debug mode counts as real, but an easy way is to include an if statement in your code that checkes for System.Diagnostics.Debugger.IsAttached.
If you created a property that you don't need at all at design time, you can use the DesignerSerializationVisibility attribute and set it to Hidden. For example:
protected virtual DataGridView GetGrid()
{
throw new NotImplementedException("frmBase.GetGrid()");
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public int ColumnCount { get { return GetGrid().Columns.Count; } set { /*Some code*/ } }
It stopped my Visual Studio crashing every time I made a change to the form with NotImplementedException() and tried to save. Instead, Visual Studio knows that I don't want to serialize this property, so it can skip it. It only displays some weird string in the properties box of the form, but it seems to be safe to ignore.
Please note that this change does not take effect until you rebuild.
We use the following code in UserControls and it does the work. Using only DesignMode will not work in your app that uses your custom user controls as pointed out by other members.
public bool IsDesignerHosted
{
get { return IsControlDesignerHosted(this); }
}
public bool IsControlDesignerHosted(System.Windows.Forms.Control ctrl)
{
if (ctrl != null)
{
if (ctrl.Site != null)
{
if (ctrl.Site.DesignMode == true)
return true;
else
{
if (IsControlDesignerHosted(ctrl.Parent))
return true;
else
return false;
}
}
else
{
if (IsControlDesignerHosted(ctrl.Parent))
return true;
else
return false;
}
}
else
return false;
}
Basically the logic above boils down to:
public bool IsControlDesignerHosted(System.Windows.Forms.Control ctrl)
{
if (ctrl == null) return false;
if (ctrl.Site != null && ctrl.Site.DesignMode) return true;
return IsControlDesignerHosted(ctrl.Parent);
}
If you are in a form or control you can use the DesignMode property:
if (DesignMode)
{
DesignMode Only stuff
}
I found the DesignMode property to be buggy, at least in previous versions of Visual Studio. Hence, I made my own using the following logic:
Process.GetCurrentProcess().ProcessName.ToLower().Trim() == "devenv";
Kind of a hack, I know, but it works well.
System.ComponentModel.Component.DesignMode == true
To solve the problem, you can also code as below:
private bool IsUnderDevelopment
{
get
{
System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess();
if (process.ProcessName.EndsWith(".vshost")) return true;
else return false;
}
}
Here's another one:
//Caters only to thing done while only in design mode
if (App.Current.MainWindow == null){ // in design mode }
//Avoids design mode problems
if (App.Current.MainWindow != null) { //applicaiton is running }
After testing most of the answers here, unfortunately nothing worked for me (VS2015).
So I added a little twist to JohnV's answer, which didn't work out of the box, since DesignMode is a protected Property in the Control class.
First I made an extension method which returns the DesignMode's Property value via Reflection:
public static Boolean GetDesignMode(this Control control)
{
BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static;
PropertyInfo prop = control.GetType().GetProperty("DesignMode", bindFlags);
return (Boolean)prop.GetValue(control, null);
}
and then I made a function like JohnV:
public bool HostedDesignMode
{
get
{
Control parent = Parent;
while (parent != null)
{
if (parent.GetDesignMode()) return true;
parent = parent.Parent;
}
return DesignMode;
}
}
This is the only method that worked for me, avoiding all the ProcessName mess, and while reflection should not be used lightly, in this case it did all the difference! ;)
EDIT:
You can also make the second function an extension method like this:
public static Boolean IsInDesignMode(this Control control)
{
Control parent = control.Parent;
while (parent != null)
{
if (parent.GetDesignMode())
{
return true;
}
parent = parent.Parent;
}
return control.GetDesignMode();
}
For WPF (hopefully this is useful for those WPF people stumbling upon this question):
if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(new DependencyObject()))
{
}
GetIsInDesignMode requires a DependencyObject. If you don't have one, just create one.
/// <summary>
/// Whether or not we are being run from the Visual Studio IDE
/// </summary>
public bool InIDE
{
get
{
return Process.GetCurrentProcess().ProcessName.ToLower().Trim().EndsWith("vshost");
}
}
Here's a flexible way that is adaptable to where you compile from as well as whether or not you care which mode you're in.
string testString1 = "\\bin\\";
//string testString = "\\bin\\Debug\\";
//string testString = "\\bin\\Release\\";
if (AppDomain.CurrentDomain.BaseDirectory.Contains(testString))
{
//Your code here
}

Resources